Compare commits

...

25 Commits

Author SHA1 Message Date
寂静的羽夏 56304a75d0 fix: 缩小字体设置范围; 2025-05-11 13:13:52 +08:00
寂静的羽夏 57bd7b7c61 fix: 修复设置无法重置的问题;一些增强和修复; 2025-05-10 21:07:41 +08:00
寂静的羽夏 066ab5375b fix: 修复代码提示相关和字节搜索框问题; 2025-05-09 12:40:39 +08:00
寂静的羽夏 1be1f7322f fix: 修复和增强编辑器相关问题; 2025-05-09 12:18:17 +08:00
寂静的羽夏 b49523e952 fix: 修复增强预处理器和缺失的字符串函数 2025-05-06 13:44:59 +08:00
寂静的羽夏 960de3afb6 fix: 修复损坏的搜索上下文显示;增强脚本宏和增加内置宏; 2025-05-05 15:05:33 +08:00
寂静的羽夏 3f26766575 feat: print 多参数和 promise 支持;修复终端主题设置; 2025-05-04 11:53:30 +08:00
寂静的羽夏 098f08e906 ci: 更新 setup-python 2025-05-02 19:38:57 +08:00
寂静的羽夏 cb2e8743af feat: 功能微调和更新 2025-05-02 19:16:28 +08:00
寂静的羽夏 8ad73431c1 feat: 更新语言文件和README; 2025-05-02 18:11:43 +08:00
寂静的羽夏 db60affc22 fix: 修复通配符匹配功能损坏问题; 2025-05-02 17:53:15 +08:00
寂静的羽夏 32e27ba543 feat: 代码填充完善;脚本功能增强; 2025-05-02 14:02:31 +08:00
寂静的羽夏 c01ca038a3 feat: 一些 Bug 修复和脚本处理相关 2025-04-30 17:25:39 +08:00
寂静的羽夏 d8069aedde feat: 更好用的代码填充;更强大的控制台;一些 Bug 修复; 2025-04-27 23:32:03 +08:00
寂静的羽夏 cf3d4da8e8 fix: 更好的代码填充和一些 Bug 修复; 2025-04-27 11:31:15 +08:00
寂静的羽夏 2ee3051a7d feat: 更好的代码填充;自动重载文件相关; 2025-04-24 21:10:54 +08:00
寂静的羽夏 f59755e3f0 fix: 更好的代码提示支持;修复禁用脚本功能导致的程序崩溃; 2025-04-19 18:57:10 +08:00
寂静的羽夏 ef8bb9aa3a feat: 更好的代码填充; 2025-04-16 13:44:40 +08:00
寂静的羽夏 f87c0970be feat: 更好的代码填充; 2025-04-12 18:50:47 +08:00
寂静的羽夏 f51630c6f0 feat: 移除数据可视化功能以轻量化;优化 WingAngelAPI 脚本注册; 2025-04-10 12:51:13 +08:00
寂静的羽夏 d6680e3f11 feat: 脚本引擎单例化;更合理的格式化参数; 2025-04-09 14:05:30 +08:00
寂静的羽夏 7597663d76 feat: 数值增加无符号切换格式;初步代码内容提示; 2025-04-06 20:11:30 +08:00
寂静的羽夏 7ee69b5ced fix: 修复克隆页右键菜单无效;修复终端主题修改输出颜色不改变; 2025-03-31 13:27:39 +08:00
寂静的羽夏 570f78994c fix: 优化文本预览功能体验; 2025-03-30 13:27:49 +08:00
寂静的羽夏 5aaa59937d fix: 修复终端输出颜色不跟随主题;修复光标字节大小显示; 2025-03-30 10:18:20 +08:00
129 changed files with 10112 additions and 10171 deletions

View File

@ -40,7 +40,7 @@ jobs:
run: sudo apt install fakeroot patchelf -y run: sudo apt install fakeroot patchelf -y
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v2 uses: actions/setup-python@v5
with: with:
python-version: '3.8' python-version: '3.8'
cache: 'pip' cache: 'pip'

View File

@ -43,7 +43,7 @@ jobs:
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v2 uses: actions/setup-python@v5
with: with:
python-version: '3.8' python-version: '3.8'
cache: 'pip' cache: 'pip'
@ -64,4 +64,4 @@ jobs:
with: with:
name: WingHexExplorer2-win-release-build-cache name: WingHexExplorer2-win-release-build-cache
path: ${{github.workspace}}/mkinstaller/innoSetup/*.exe path: ${{github.workspace}}/mkinstaller/innoSetup/*.exe

View File

@ -109,6 +109,15 @@ QString QConsoleWidget::getCommandLine() {
return code; return code;
} }
void QConsoleWidget::paste() {
QTextCursor textCursor = this->textCursor();
const QMimeData *const clipboard = QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text, channelCharFormat(StandardInput));
}
}
void QConsoleWidget::handleReturnKey() { void QConsoleWidget::handleReturnKey() {
QString code = getCommandLine(); QString code = getCommandLine();
@ -189,12 +198,7 @@ void QConsoleWidget::keyPressEvent(QKeyEvent *e) {
// Allow paste only if the selection is in the interactive area ... // Allow paste only if the selection is in the interactive area ...
if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) { if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) {
if (selectionInEditZone || isCursorInEditZone()) { if (selectionInEditZone || isCursorInEditZone()) {
const QMimeData *const clipboard = paste();
QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isNull()) {
textCursor.insertText(text, channelCharFormat(StandardInput));
}
} }
e->accept(); e->accept();
@ -361,16 +365,15 @@ void QConsoleWidget::replaceCommandLine(const QString &str) {
} }
QString QConsoleWidget::currentCommandLine() const { QString QConsoleWidget::currentCommandLine() const {
// Select the text after the last command prompt ...
QTextCursor textCursor = this->textCursor(); QTextCursor textCursor = this->textCursor();
textCursor.movePosition(QTextCursor::End); textCursor.movePosition(QTextCursor::End);
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor); textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
return textCursor.selectedText(); return textCursor.selectedText();
} }
int QConsoleWidget::currentHeaderPos() const { return inpos_; }
void QConsoleWidget::write(const QString &message, const QTextCharFormat &fmt) { void QConsoleWidget::write(const QString &message, const QTextCharFormat &fmt) {
QTextCharFormat currfmt = currentCharFormat();
QTextCursor tc = textCursor(); QTextCursor tc = textCursor();
if (mode() == Input) { if (mode() == Input) {
@ -396,8 +399,8 @@ void QConsoleWidget::write(const QString &message, const QTextCharFormat &fmt) {
inpos_ = tc.position() - inpos_; inpos_ = tc.position() - inpos_;
// restore the edit pos // restore the edit pos
tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, editpos); tc.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, editpos);
tc.setCharFormat({});
setTextCursor(tc); setTextCursor(tc);
setCurrentCharFormat(currfmt);
} else { } else {
// in output mode messages are ed // in output mode messages are ed
QTextCursor tc1 = tc; QTextCursor tc1 = tc;
@ -412,6 +415,8 @@ void QConsoleWidget::write(const QString &message, const QTextCharFormat &fmt) {
textCursor().insertText(message, fmt); textCursor().insertText(message, fmt);
ensureCursorVisible(); ensureCursorVisible();
tc.setCharFormat({});
// restore cursor if needed // restore cursor if needed
if (needsRestore) if (needsRestore)
setTextCursor(tc); setTextCursor(tc);

View File

@ -77,6 +77,10 @@ public:
// get the current command line // get the current command line
QString getCommandLine(); QString getCommandLine();
virtual void paste();
int currentHeaderPos() const;
public slots: public slots:
// write to StandardOutput // write to StandardOutput
@ -94,6 +98,7 @@ signals:
protected: protected:
bool canPaste() const; bool canPaste() const;
bool canCut() const; bool canCut() const;
virtual void handleReturnKey(); virtual void handleReturnKey();
virtual void handleTabKey(); virtual void handleTabKey();
// reimp QPlainTextEdit functions // reimp QPlainTextEdit functions
@ -112,7 +117,6 @@ protected:
static History history_; static History history_;
ConsoleMode mode_; ConsoleMode mode_;
int inpos_; int inpos_;
QString currentMultiLineCode_;
QConsoleIODevice *iodevice_; QConsoleIODevice *iodevice_;
QTextCharFormat chanFormat_[nConsoleChannels]; QTextCharFormat chanFormat_[nConsoleChannels];
}; };

View File

@ -61,7 +61,7 @@ qsizetype QHexCursor::selectionLength(qsizetype index) const {
qsizetype QHexCursor::currentSelectionLength() const { qsizetype QHexCursor::currentSelectionLength() const {
if (hasPreviewSelection() && m_preMode != SelectionRemove) { if (hasPreviewSelection() && m_preMode != SelectionRemove) {
return qAbs(m_position - m_selection + 1); return qAbs(m_position - m_selection) + 1;
} }
qsizetype len = 0; qsizetype len = 0;

View File

@ -437,44 +437,30 @@ void QHexDocument::findAllBytes(qsizetype begin, qsizetype end,
} }
} }
qsizetype QHexDocument::findAllBytesExt(qsizetype begin, qsizetype end, void QHexDocument::findAllBytesExt(qsizetype begin, qsizetype end,
const QString &pattern, const QString &pattern,
QList<qsizetype> &results, QList<qsizetype> &results,
const std::function<bool()> &pred) { const std::function<bool()> &pred) {
results.clear(); results.clear();
auto patterns = parseConvertPattern(pattern); if (end < 0) {
if (patterns.isEmpty()) { end = m_buffer->length();
return 0;
} }
qsizetype p = begin > 0 ? begin : 0; if (pattern.isEmpty() || end > m_buffer->length() || begin >= end) {
qsizetype e = end > begin ? end : -1; return;
qsizetype offset = 0;
for (auto &p : patterns) {
if (std::holds_alternative<QByteArray>(p)) {
offset += std::get<QByteArray>(p).length();
} else if (std::holds_alternative<size_t>(p)) {
offset += std::get<size_t>(p);
} else if (std::holds_alternative<HexWildItem>(p)) {
offset += 1;
}
} }
qsizetype pos = begin;
while (pred()) { qsizetype n = pattern.size();
p = findNextExt(p, pattern); while (pos + n <= end && pred()) {
if (p < 0 || (e > 0 && p > e)) { qsizetype f = findNextExt(pos, pattern);
if (f < 0 || f + n > end)
break;
results.append(f);
pos = f + 1;
if (results.size() >= QHEXVIEW_FIND_LIMIT) {
break; break;
} }
if (results.size() > QHEXVIEW_FIND_LIMIT) {
break;
}
results.append(p);
p += offset;
} }
return offset;
} }
bool QHexDocument::insert(qsizetype offset, uchar b) { bool QHexDocument::insert(qsizetype offset, uchar b) {
@ -538,287 +524,92 @@ bool QHexDocument::_remove(qsizetype offset, qsizetype len) {
return true; return true;
} }
qsizetype QHexDocument::findNextExt(qsizetype begin, bool QHexDocument::parsePattern(const QString &pattern,
const QList<FindStep> &patterns) { QList<PatternByte> &out) {
auto op = [this](qsizetype &pos, const FindStep &step, out.clear();
qsizetype *begin = nullptr) -> bool { QString p = pattern;
if (pos < 0 || pos >= length()) { p.remove(' ');
return false; if (p.size() % 2 != 0) {
} return false;
if (std::holds_alternative<QByteArray>(step)) { }
auto v = std::get<QByteArray>(step); for (int i = 0; i < p.size(); i += 2) {
auto len = v.length(); QChar hi = p[i], lo = p[i + 1];
auto r = findNext(pos, v); PatternByte pb;
if (r >= 0) { // high nibble
if (begin) { if (hi != '?') {
*begin = r; int v = hex2Int(hi);
} else { if (v < 0) {
if (r != pos) {
pos = -1;
return false;
}
}
pos = r + len;
return true;
} else {
pos = -1;
return false; return false;
} }
} else if (std::holds_alternative<HexWildItem>(step)) { pb.value |= quint8(v << 4);
auto v = std::get<HexWildItem>(step); pb.mask |= 0xF0;
auto wc = uchar(at(pos));
pos += 1;
if (v.higher == '?') {
if ((wc & 0xf) == v.lower) {
return true;
}
} else {
if ((wc >> 4) == v.higher) {
return true;
}
}
} else if (std::holds_alternative<size_t>(step)) {
auto v = std::get<size_t>(step);
pos += v;
if (v + pos < length()) {
return true;
}
} }
return false; // low nibble
}; if (lo != '?') {
int v = hex2Int(lo);
while (begin < length()) { if (v < 0) {
auto pos = begin; return false;
auto p = patterns.cbegin();
auto r = op(pos, *p, &begin);
if (!r) {
if (pos < 0) {
return -1;
} }
continue; pb.value |= quint8(v);
pb.mask |= 0x0F;
} }
++p; out.append(pb);
}
return true;
}
int QHexDocument::hex2Int(const QChar &c) {
ushort u = c.unicode();
if (u >= '0' && u <= '9')
return u - '0';
else if (u >= 'A' && u <= 'F')
return 10 + (u - 'A');
else if (u >= 'a' && u <= 'f')
return 10 + (u - 'a');
else
return -1;
}
qsizetype QHexDocument::findNextExt(qsizetype begin,
const QList<PatternByte> &patterns) {
if (patterns.isEmpty() || begin < 0 ||
begin + patterns.size() > m_buffer->length())
return -1;
qsizetype n = patterns.size();
for (qsizetype pos = begin; pos + n <= m_buffer->length(); ++pos) {
bool ok = true; bool ok = true;
for (; p != patterns.cend(); ++p) { for (qsizetype i = 0; i < n; ++i) {
auto r = op(pos, *p); if (!matchByte(m_buffer->at(pos + i), patterns[i])) {
if (!r) {
ok = false; ok = false;
if (pos < 0) {
return -1;
}
begin = pos;
break; break;
} }
} }
if (ok)
if (ok) { return pos;
return begin;
}
} }
return -1; return -1;
} }
qsizetype QHexDocument::findPreviousExt(qsizetype begin, qsizetype QHexDocument::findPreviousExt(qsizetype begin,
const QList<FindStep> &patterns) { const QList<PatternByte> &patterns) {
auto op = [this](qsizetype &pos, const FindStep &step, if (patterns.isEmpty() || begin < 0)
qsizetype *begin = nullptr) -> bool { return -1;
if (pos < 0 || pos >= length()) { qsizetype n = patterns.size();
return false; qsizetype maxStart = qMin(begin, m_buffer->length() - n);
} for (qsizetype pos = maxStart; pos >= 0; --pos) {
if (std::holds_alternative<QByteArray>(step)) {
auto v = std::get<QByteArray>(step);
auto len = v.length();
auto r = findPrevious(pos, v);
if (r >= 0) {
if (begin) {
*begin = r;
} else {
if (r + len != pos) {
pos = -1;
return false;
}
}
pos = r - len;
return true;
} else {
pos = -1;
return false;
}
} else if (std::holds_alternative<HexWildItem>(step)) {
auto v = std::get<HexWildItem>(step);
auto wc = uchar(at(pos));
pos -= 1;
if (v.higher == '?') {
if ((wc & 0xf) == v.lower) {
return true;
}
} else {
if ((wc >> 4) == v.higher) {
return true;
}
}
} else if (std::holds_alternative<size_t>(step)) {
auto v = std::get<size_t>(step);
pos -= v;
if (v - pos >= 0) {
return true;
}
}
return false;
};
while (begin >= 0) {
auto pos = begin;
auto p = patterns.crbegin();
auto r = op(pos, *p, &begin);
if (!r) {
if (pos < 0) {
return -1;
}
continue;
}
++p;
bool ok = true; bool ok = true;
for (; p != patterns.crend(); ++p) { for (qsizetype i = 0; i < n; ++i) {
auto r = op(pos, *p); if (!matchByte(m_buffer->at(pos + i), patterns[i])) {
if (!r) {
ok = false; ok = false;
if (pos < 0) {
return -1;
}
begin = pos;
break; break;
} }
} }
if (ok)
if (ok) { return pos;
return begin;
}
} }
return -1; return -1;
} }
QList<QHexDocument::FindStep>
QHexDocument::parseConvertPattern(const QString &pattern) {
// process hex pattern
QList<HexWildItem> words;
std::optional<uchar> higher;
for (auto pchar = pattern.cbegin(); pchar != pattern.cend(); ++pchar) {
if (pchar->isSpace()) {
if (higher) {
return {};
} else {
continue;
}
}
auto c = pchar->unicode();
if (c >= '0' && c <= '9') {
if (higher) {
HexWildItem item;
item.higher = higher.value();
item.lower = uchar(c) - '0';
words.append(item);
higher.reset();
} else {
higher = uchar(c) - '0';
}
} else if (c >= 'A' && c <= 'F') {
if (higher) {
HexWildItem item;
item.higher = higher.value();
item.lower = uchar(c) - 'A' + 10;
words.append(item);
higher.reset();
} else {
higher = uchar(c) - 'A' + 10;
}
} else if (c >= 'a' && c <= 'f') {
if (higher) {
HexWildItem item;
item.higher = higher.value();
item.lower = uchar(c) - 'a' + 10;
words.append(item);
higher.reset();
} else {
higher = uchar(c) - 'a' + 10;
}
} else if (c == '?') {
if (higher) {
HexWildItem item;
item.higher = higher.value();
item.lower = '?';
words.append(item);
higher.reset();
} else {
higher = '?';
}
}
}
if (higher) {
return {};
}
if (!words.isEmpty()) {
QList<FindStep> steps;
// parsing...
QByteArray buffer;
size_t len = 0;
for (auto pw = words.cbegin(); pw != words.cend(); ++pw) {
auto higher = pw->higher;
auto lower = pw->lower;
if (higher == '?' || lower == '?') {
if (higher == '?' && lower == '?') {
if (!buffer.isEmpty()) {
steps.append(buffer);
buffer.clear();
}
len++;
} else {
if (len != 0) {
steps.append(len);
len = 0;
}
if (!buffer.isEmpty()) {
steps.append(buffer);
buffer.clear();
}
HexWildItem item;
item.higher = higher;
item.lower = lower;
steps.append(item);
}
} else {
if (len != 0) {
steps.append(len);
len = 0;
}
buffer.append(char(pw->higher << 4 | pw->lower));
}
}
// clean up
if (len != 0) {
steps.append(len);
}
if (!buffer.isEmpty()) {
steps.append(buffer);
}
return steps;
}
return {};
}
/*======================*/ /*======================*/
// modified by wingsummer // modified by wingsummer
@ -913,27 +704,31 @@ void QHexDocument::beginMarco(const QString &text) {
void QHexDocument::endMarco() { m_undostack->endMacro(); } void QHexDocument::endMarco() { m_undostack->endMacro(); }
void QHexDocument::Insert(QHexCursor *cursor, qsizetype offset, uchar b, bool QHexDocument::Insert(QHexCursor *cursor, qsizetype offset, uchar b,
int nibbleindex) { int nibbleindex) {
this->Insert(cursor, offset, QByteArray(1, char(b)), nibbleindex); return this->Insert(cursor, offset, QByteArray(1, char(b)), nibbleindex);
} }
void QHexDocument::Replace(QHexCursor *cursor, qsizetype offset, uchar b, bool QHexDocument::Replace(QHexCursor *cursor, qsizetype offset, uchar b,
int nibbleindex) { int nibbleindex) {
this->Replace(cursor, offset, QByteArray(1, char(b)), nibbleindex); return this->Replace(cursor, offset, QByteArray(1, char(b)), nibbleindex);
} }
void QHexDocument::Insert(QHexCursor *cursor, qsizetype offset, bool QHexDocument::Insert(QHexCursor *cursor, qsizetype offset,
const QByteArray &data, int nibbleindex) { const QByteArray &data, int nibbleindex) {
if (m_keepsize || m_readonly || m_islocked) if (m_keepsize || m_readonly || m_islocked) {
return; return false;
}
auto cmd = MakeInsert(nullptr, cursor, offset, data, nibbleindex); auto cmd = MakeInsert(nullptr, cursor, offset, data, nibbleindex);
if (cmd) { if (cmd) {
m_undostack->push(cmd); m_undostack->push(cmd);
} else {
return false;
} }
emit documentChanged(); emit documentChanged();
return true;
} }
void QHexDocument::Append(QHexCursor *cursor, uchar b, int nibbleindex) { void QHexDocument::Append(QHexCursor *cursor, uchar b, int nibbleindex) {
@ -951,15 +746,19 @@ void QHexDocument::Append(QHexCursor *cursor, const QByteArray &data,
emit documentChanged(); emit documentChanged();
} }
void QHexDocument::Replace(QHexCursor *cursor, qsizetype offset, bool QHexDocument::Replace(QHexCursor *cursor, qsizetype offset,
const QByteArray &data, int nibbleindex) { const QByteArray &data, int nibbleindex) {
if (m_readonly || m_islocked) if (m_readonly || m_islocked) {
return; return false;
}
auto cmd = MakeReplace(nullptr, cursor, offset, data, nibbleindex); auto cmd = MakeReplace(nullptr, cursor, offset, data, nibbleindex);
if (cmd) { if (cmd) {
m_undostack->push(cmd); m_undostack->push(cmd);
} else {
return false;
} }
emit documentChanged(); emit documentChanged();
return true;
} }
bool QHexDocument::Remove(QHexCursor *cursor, qsizetype offset, qsizetype len, bool QHexDocument::Remove(QHexCursor *cursor, qsizetype offset, qsizetype len,
@ -1063,21 +862,19 @@ qsizetype QHexDocument::findPrevious(qsizetype begin, const QByteArray &ba) {
} }
qsizetype QHexDocument::findNextExt(qsizetype begin, const QString &pattern) { qsizetype QHexDocument::findNextExt(qsizetype begin, const QString &pattern) {
auto patterns = parseConvertPattern(pattern); QList<PatternByte> patterns;
if (patterns.isEmpty()) { if (!parsePattern(pattern, patterns)) {
return -1; return -1;
} }
return findNextExt(begin, patterns); return findNextExt(begin, patterns);
} }
qsizetype QHexDocument::findPreviousExt(qsizetype begin, qsizetype QHexDocument::findPreviousExt(qsizetype begin,
const QString &pattern) { const QString &pattern) {
auto patterns = parseConvertPattern(pattern); QList<PatternByte> patterns;
if (patterns.isEmpty()) { if (!parsePattern(pattern, patterns)) {
return -1; return -1;
} }
return findPreviousExt(begin, patterns); return findPreviousExt(begin, patterns);
} }

View File

@ -107,7 +107,7 @@ public:
QList<qsizetype> &results, QList<qsizetype> &results,
const std::function<bool()> &pred = [] { return true; }); const std::function<bool()> &pred = [] { return true; });
qsizetype findAllBytesExt( void findAllBytesExt(
qsizetype begin, qsizetype end, const QString &pattern, qsizetype begin, qsizetype end, const QString &pattern,
QList<qsizetype> &results, QList<qsizetype> &results,
const std::function<bool()> &pred = [] { return true; }); const std::function<bool()> &pred = [] { return true; });
@ -148,14 +148,14 @@ public slots:
void beginMarco(const QString &text); void beginMarco(const QString &text);
void endMarco(); void endMarco();
void Insert(QHexCursor *cursor, qsizetype offset, uchar b, int nibbleindex); bool Insert(QHexCursor *cursor, qsizetype offset, uchar b, int nibbleindex);
void Insert(QHexCursor *cursor, qsizetype offset, const QByteArray &data, bool Insert(QHexCursor *cursor, qsizetype offset, const QByteArray &data,
int nibbleindex); int nibbleindex);
void Append(QHexCursor *cursor, uchar b, int nibbleindex); void Append(QHexCursor *cursor, uchar b, int nibbleindex);
void Append(QHexCursor *cursor, const QByteArray &data, int nibbleindex); void Append(QHexCursor *cursor, const QByteArray &data, int nibbleindex);
void Replace(QHexCursor *cursor, qsizetype offset, uchar b, bool Replace(QHexCursor *cursor, qsizetype offset, uchar b,
int nibbleindex); int nibbleindex);
void Replace(QHexCursor *cursor, qsizetype offset, const QByteArray &data, bool Replace(QHexCursor *cursor, qsizetype offset, const QByteArray &data,
int nibbleindex = 0); int nibbleindex = 0);
bool Remove(QHexCursor *cursor, qsizetype offset, qsizetype len, bool Remove(QHexCursor *cursor, qsizetype offset, qsizetype len,
int nibbleindex = 0); int nibbleindex = 0);
@ -204,20 +204,28 @@ public slots:
bool _remove(qsizetype offset, qsizetype len); bool _remove(qsizetype offset, qsizetype len);
private: private:
// AB // PatternByte: represents a byte in the pattern, with nibble-level wildcard
struct HexWildItem { // support
uchar higher; // A struct PatternByte {
uchar lower; // B quint8 value = 0; // fixed bits
quint8 mask =
0; // mask: which bits to match (1 = must match, 0 = wildcard)
}; };
// std::variant< find-content, hex with wildcard, all-wildcards > // Parse pattern string (e.g., "00 ?? AB C? 88" or "00??ABC?88") into
using FindStep = std::variant<QByteArray, HexWildItem, size_t>; // PatternByte list
bool parsePattern(const QString &pattern, QList<PatternByte> &out);
QList<FindStep> parseConvertPattern(const QString &pattern); // Byte match using mask
qsizetype findNextExt(qsizetype begin, const QList<FindStep> &patterns); inline bool matchByte(quint8 data, const PatternByte &pb) {
qsizetype findPreviousExt(qsizetype begin, const QList<FindStep> &patterns); return (data & pb.mask) == (pb.value & pb.mask);
}
/*================================*/ int hex2Int(const QChar &c);
qsizetype findNextExt(qsizetype begin, const QList<PatternByte> &patterns);
qsizetype findPreviousExt(qsizetype begin,
const QList<PatternByte> &patterns);
/*================================*/ /*================================*/
// modified by wingsummer // modified by wingsummer

View File

@ -707,7 +707,6 @@ void QHexRenderer::drawHex(QPainter *painter, const QRect &linerect,
if (!dis) if (!dis)
this->applyMetadata(textcursor, line, Hex); this->applyMetadata(textcursor, line, Hex);
this->applyBookMark(textcursor, line, Hex);
this->applySelection(textcursor, line, Hex); this->applySelection(textcursor, line, Hex);
this->applyCursorHex(textcursor, line); this->applyCursorHex(textcursor, line);
@ -718,24 +717,76 @@ void QHexRenderer::drawHex(QPainter *painter, const QRect &linerect,
ctx.palette.setColor(QPalette::Text, m_bytesColor); ctx.palette.setColor(QPalette::Text, m_bytesColor);
textdocument.documentLayout()->draw(painter, ctx); textdocument.documentLayout()->draw(painter, ctx);
this->applyBookMark(painter, textcursor, line, Hex);
painter->restore(); painter->restore();
} }
void QHexRenderer::applyBookMark(QTextCursor &textcursor, qsizetype line, void QHexRenderer::applyBookMark(QPainter *painter, QTextCursor &textcursor,
Factor factor) { qsizetype line, Factor factor) {
if (!m_document->lineHasBookMark(line)) if (!m_document->lineHasBookMark(line))
return; return;
painter->save();
auto pos = m_document->getLineBookmarksPos(line); auto pos = m_document->getLineBookmarksPos(line);
for (auto &item : pos) { for (auto &item : pos) {
textcursor.setPosition(int((item % hexLineWidth()) * factor) + 2); auto off = item % hexLineWidth();
qreal begin, width;
auto height = lineHeight();
// add some paddings
if (factor == Hex) {
begin = getCellWidth() * off * 3 + 1;
begin += getCellWidth() / 2;
width = getCellWidth() * 2 + 2;
textcursor.setPosition(off * factor);
} else {
begin = getCellWidth() * off + 1;
width = getCellWidth();
textcursor.setPosition(m_cursor->currentColumn());
}
auto charformat = textcursor.charFormat(); auto charformat = textcursor.charFormat();
textcursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, auto textOutline = charformat.textOutline();
factor - 1);
charformat.setFontWeight(QFont::Bold); constexpr auto ALPHA = 180;
textcursor.setCharFormat(charformat);
if (textOutline.style() != Qt::NoPen) {
auto outColor = textOutline.color();
outColor.setAlpha(ALPHA);
QPen pen(outColor, 1, Qt::DotLine);
painter->setPen(pen);
} else {
if (m_cursor->currentLine() == line &&
m_cursor->currentColumn() == off) {
auto color = m_bytesColor;
color.setAlpha(ALPHA);
QPen pen(color, 1, Qt::DotLine);
painter->setPen(pen);
} else {
auto foreground = charformat.foreground();
if (foreground.style() != Qt::NoBrush) {
auto textColor = foreground.color();
textColor.setAlpha(ALPHA);
QPen pen(textColor, 1, Qt::DotLine);
painter->setPen(pen);
} else {
auto color = m_bytesColor;
color.setAlpha(ALPHA);
QPen pen(color, 1, Qt::DotLine);
painter->setPen(pen);
}
}
}
painter->setBrush(Qt::transparent);
painter->setBackground(Qt::transparent);
painter->drawRect(begin, 0, width, height);
} }
painter->restore();
} }
void QHexRenderer::drawString(QPainter *painter, const QRect &linerect, void QHexRenderer::drawString(QPainter *painter, const QRect &linerect,
@ -770,6 +821,7 @@ void QHexRenderer::drawString(QPainter *painter, const QRect &linerect,
ctx.palette.setColor(QPalette::Text, m_bytesColor); ctx.palette.setColor(QPalette::Text, m_bytesColor);
textdocument.documentLayout()->draw(painter, ctx); textdocument.documentLayout()->draw(painter, ctx);
this->applyBookMark(painter, textcursor, line, String);
painter->restore(); painter->restore();
} }

View File

@ -144,8 +144,10 @@ private:
qsizetype lineStart, qsizetype lineEnd, Factor factor, qsizetype lineStart, qsizetype lineEnd, Factor factor,
bool strikeOut, bool hasSelection) const; bool strikeOut, bool hasSelection) const;
void applyBookMark(QTextCursor &textcursor, qsizetype line, // added by wingsummer
Factor factor); // added by wingsummer void applyBookMark(QPainter *painter, QTextCursor &textcursor,
qsizetype line, Factor factor);
void applyCursorAscii(QTextCursor &textcursor, qsizetype line) const; void applyCursorAscii(QTextCursor &textcursor, qsizetype line) const;
void applyCursorHex(QTextCursor &textcursor, qsizetype line) const; void applyCursorHex(QTextCursor &textcursor, qsizetype line) const;
void drawAddress(QPainter *painter, const QRect &linerect, qsizetype line); void drawAddress(QPainter *painter, const QRect &linerect, qsizetype line);

View File

@ -355,7 +355,7 @@ qsizetype QHexView::findPrevious(qsizetype begin, const QByteArray &ba) {
bool QHexView::RemoveSelection(int nibbleindex) { bool QHexView::RemoveSelection(int nibbleindex) {
if (!m_cursor->hasSelection()) if (!m_cursor->hasSelection())
return false; return true;
auto total = m_cursor->selectionCount(); auto total = m_cursor->selectionCount();
m_document->beginMarco(QStringLiteral("RemoveSelection")); m_document->beginMarco(QStringLiteral("RemoveSelection"));
@ -375,7 +375,7 @@ bool QHexView::RemoveSelection(int nibbleindex) {
bool QHexView::removeSelection() { bool QHexView::removeSelection() {
if (!m_cursor->hasSelection()) if (!m_cursor->hasSelection())
return false; return true;
// We essure selections are ordered by desending // We essure selections are ordered by desending
// by selection-start, so it's safe to remove // by selection-start, so it's safe to remove
@ -417,7 +417,7 @@ QByteArrayList QHexView::selectedBytes() const {
return res; return res;
} }
void QHexView::paste(bool hex) { bool QHexView::paste(bool hex) {
QClipboard *c = qApp->clipboard(); QClipboard *c = qApp->clipboard();
QByteArray data; QByteArray data;
@ -426,19 +426,28 @@ void QHexView::paste(bool hex) {
} else { } else {
auto d = c->mimeData(); auto d = c->mimeData();
data = d->data(QStringLiteral("application/octet-stream")); data = d->data(QStringLiteral("application/octet-stream"));
if (data.isEmpty()) {
data = d->text().toUtf8();
}
} }
if (data.isEmpty()) if (data.isEmpty()) {
return; return true;
}
this->removeSelection(); auto ret = this->removeSelection();
if (!ret) {
return false;
}
auto pos = m_cursor->position().offset(); auto pos = m_cursor->position().offset();
if (!m_document->isKeepSize()) { if (!m_document->isKeepSize()) {
m_document->insert(pos, data); bool ret = m_document->insert(pos, data);
m_cursor->moveTo(pos + data.length()); // added by wingsummer m_cursor->moveTo(pos + data.length()); // added by wingsummer
} else return ret;
m_document->replace(pos, data); } else {
return m_document->replace(pos, data);
}
} }
bool QHexView::Cut(bool hex, int nibbleindex) { bool QHexView::Cut(bool hex, int nibbleindex) {
@ -457,7 +466,7 @@ bool QHexView::Cut(bool hex, int nibbleindex) {
} }
} }
void QHexView::Paste(bool hex, int nibbleindex) { bool QHexView::Paste(bool hex, int nibbleindex) {
QClipboard *c = qApp->clipboard(); QClipboard *c = qApp->clipboard();
QByteArray data; QByteArray data;
@ -466,19 +475,27 @@ void QHexView::Paste(bool hex, int nibbleindex) {
} else { } else {
auto d = c->mimeData(); auto d = c->mimeData();
data = d->data(QStringLiteral("application/octet-stream")); data = d->data(QStringLiteral("application/octet-stream"));
if (data.isEmpty()) {
data = d->text().toUtf8();
}
} }
if (data.isEmpty()) if (data.isEmpty()) {
return; return true;
}
this->RemoveSelection(nibbleindex); auto ret = this->RemoveSelection(nibbleindex);
if (!ret) {
return false;
}
auto pos = m_cursor->position().offset(); auto pos = m_cursor->position().offset();
if (m_cursor->insertionMode() == QHexCursor::InsertionMode::InsertMode) { if (m_cursor->insertionMode() == QHexCursor::InsertionMode::InsertMode) {
m_document->Insert(m_cursor, pos, data, nibbleindex); auto ret = m_document->Insert(m_cursor, pos, data, nibbleindex);
m_cursor->moveTo(pos + data.length()); // added by wingsummer m_cursor->moveTo(pos + data.length()); // added by wingsummer
return ret;
} else { } else {
m_document->Replace(m_cursor, pos, data, nibbleindex); return m_document->Replace(m_cursor, pos, data, nibbleindex);
} }
} }
@ -537,10 +554,11 @@ bool QHexView::copy(bool hex) {
qreal QHexView::fontSize() const { return m_fontSize; } qreal QHexView::fontSize() const { return m_fontSize; }
void QHexView::setScaleRate(qreal rate) { void QHexView::setScaleRate(qreal rate) {
if (m_scaleRate > 0) { if (rate >= 0.2 && rate < 2.01) {
m_scaleRate = rate; m_scaleRate = rate;
setFontSize(fontSize()); setFontSize(fontSize());
emit scaleRateChanged(); emit scaleRateChanged();
update();
} }
} }
@ -709,7 +727,7 @@ void QHexView::focusOutEvent(QFocusEvent *e) {
void QHexView::wheelEvent(QWheelEvent *e) { void QHexView::wheelEvent(QWheelEvent *e) {
if (qApp->keyboardModifiers() == Qt::ControlModifier) { if (qApp->keyboardModifiers() == Qt::ControlModifier) {
auto dela = e->angleDelta().y() / 1200.0 / 2; auto dela = e->angleDelta().y() / 1200.0;
setScaleRate(scaleRate() + dela); setScaleRate(scaleRate() + dela);
return; return;
} }

View File

@ -135,10 +135,10 @@ public:
bool cut(bool hex); bool cut(bool hex);
bool copy(bool hex = false); bool copy(bool hex = false);
void paste(bool hex = false); bool paste(bool hex = false);
bool Cut(bool hex = false, int nibbleindex = 0); bool Cut(bool hex = false, int nibbleindex = 0);
void Paste(bool hex = false, int nibbleindex = 0); bool Paste(bool hex = false, int nibbleindex = 0);
void Replace(qsizetype offset, uchar b, int nibbleindex); void Replace(qsizetype offset, uchar b, int nibbleindex);
void Replace(qsizetype offset, const QByteArray &data, int nibbleindex = 0); void Replace(qsizetype offset, const QByteArray &data, int nibbleindex = 0);

View File

@ -1,155 +0,0 @@
# macOS
.DS_Store
# Windows
Thumbs.db
ehthumbs.db
# Folder config file commonly created by Windows Explorer
Desktop.ini
# Recycle Bin used on file shares and remote volumes
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# Thumbnail cache files created by Windows
Thumbs.db
Thumbs.db:encryptable
# Windows Desktop Search
*.pst
*.ost
*.log
# Compiled Object files, Static and Dynamic libs
*.o
*.lo
*.la
*.a
*.class
*.so
*.lib
*.dll
*.exe
# Python
__pycache__/
*.pyc
*.pyo
*.pyd
# Java
*.class
# Eclipse
.project
.classpath
.settings/
# IntelliJ
.idea/
# Visual Studio Code
.vscode/
.vscodium/
# Node.js
node_modules/
# Jupyter Notebook
.ipynb_checkpoints/
# Thumbnails
Thumbs/
Thumbs.db
# macOS metadata
._*
# TextMate
*.tmproj
*.tmproject
.tmtags
# Sublime Text
*.sublime-workspace
*.sublime-project
# VS Code directories
.vscode/
# CodeKit
.codekit-config.json
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Compiled files
*.com
*.class
*.dll
*.exe
*.o
*.so
# Logs and databases
*.log
*.sql
*.sqlite
*.sqlite3
*.xml
# Binary and source packages
*.dmg
*.gz
*.iso
*.jar
*.tar
*.zip
*.rar
*.bin
*.war
*.ear
*.sar
*.bbl
*.pdf
*.xls
*.xlsx
*.ppt
*.pptx
# Virtual environment
venv/
env/
### Manually Entered
vim-debug/
**/out/bin
**/out/lib
**/out/share
_deps
.cache/
compile_commands.json
*.bak
docs/
*.old
# clangd cache
.cache/
.vim/
build/
debug/
realease/
Release/
Debug

View File

@ -1,26 +0,0 @@
cmake_minimum_required(VERSION 3.26)
project(
QJsonModel
VERSION 0.0.2
LANGUAGES C CXX
# Save this for later: HOMEPAGE_URL <URL>
DESCRIPTION
"QJsonModel is a json tree model class for Qt6/C++17 based on QAbstractItemModel. MIT License."
)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
if(MSVC)
string(APPEND CMAKE_CXX_FLAGS " /utf-8")
string(APPEND CMAKE_C_FLAGS " /utf-8")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(QJsonModel STATIC include/details/QUtf8.hpp include/QJsonModel.hpp
QJsonModel.cpp)
target_link_libraries(QJsonModel PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 sacha schutz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,518 +0,0 @@
/* QJsonModel.cpp
* Copyright (c) 2011 SCHUTZ Sacha
* Copyright © 2024 Saul D. Beniquez
*
* License:
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// NOLINTBEGIN
#include "QJsonModel.hpp"
#include <QDebug>
#include <QFile>
#include <QFont>
inline bool contains(const QStringList &list, const QString &value) {
for (auto val : list)
if (value.contains(val, Qt::CaseInsensitive))
return true;
return false;
}
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent) { mParent = parent; }
QJsonTreeItem::~QJsonTreeItem() { qDeleteAll(mChilds); }
void QJsonTreeItem::appendChild(QJsonTreeItem *item) { mChilds.append(item); }
QJsonTreeItem *QJsonTreeItem::child(int row) { return mChilds.value(row); }
QJsonTreeItem *QJsonTreeItem::parent() { return mParent; }
int QJsonTreeItem::childCount() const { return mChilds.count(); }
int QJsonTreeItem::row() const {
if (mParent)
return mParent->mChilds.indexOf(const_cast<QJsonTreeItem *>(this));
return 0;
}
void QJsonTreeItem::setKey(const QString &key) { mKey = key; }
void QJsonTreeItem::setValue(const QVariant &value) { mValue = value; }
void QJsonTreeItem::setType(const QJsonValue::Type &type) { mType = type; }
QString QJsonTreeItem::key() const { return mKey; }
QVariant QJsonTreeItem::value() const { return mValue; }
QJsonValue::Type QJsonTreeItem::type() const { return mType; }
QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value,
const QStringList &exceptions,
QJsonTreeItem *parent) {
QJsonTreeItem *rootItem = new QJsonTreeItem(parent);
rootItem->setKey("root");
if (value.isObject()) {
// Get all QJsonValue childs
const QStringList keys =
value.toObject().keys(); // To prevent clazy-range warning
for (const QString &key : keys) {
if (contains(exceptions, key)) {
continue;
}
QJsonValue v = value.toObject().value(key);
QJsonTreeItem *child = load(v, exceptions, rootItem);
child->setKey(key);
child->setType(v.type());
rootItem->appendChild(child);
}
} else if (value.isArray()) {
// Get all QJsonValue childs
int index = 0;
const QJsonArray array =
value.toArray(); // To prevent clazy-range warning
for (const QJsonValue &v : array) {
QJsonTreeItem *child = load(v, exceptions, rootItem);
child->setKey(QString::number(index));
child->setType(v.type());
rootItem->appendChild(child);
++index;
}
} else {
rootItem->setValue(value.toVariant());
rootItem->setType(value.type());
}
return rootItem;
}
//=========================================================================
inline uchar hexdig(uint u) { return (u < 0xa ? '0' + u : 'a' + u - 0xa); }
QByteArray escapedString(const QString &s) {
QByteArray ba(s.length(), Qt::Uninitialized);
uchar *cursor =
reinterpret_cast<uchar *>(const_cast<char *>(ba.constData()));
const uchar *ba_end = cursor + ba.length();
const ushort *src = reinterpret_cast<const ushort *>(s.constBegin());
const ushort *const end = reinterpret_cast<const ushort *>(s.constEnd());
while (src != end) {
if (cursor >= ba_end - 6) {
// ensure we have enough space
int pos = cursor - reinterpret_cast<const uchar *>(ba.constData());
ba.resize(ba.size() * 2);
cursor = reinterpret_cast<uchar *>(ba.data()) + pos;
ba_end =
reinterpret_cast<const uchar *>(ba.constData()) + ba.length();
}
uint u = *src++;
if (u < 0x80) {
if (u < 0x20 || u == 0x22 || u == 0x5c) {
*cursor++ = '\\';
switch (u) {
case 0x22:
*cursor++ = '"';
break;
case 0x5c:
*cursor++ = '\\';
break;
case 0x8:
*cursor++ = 'b';
break;
case 0xc:
*cursor++ = 'f';
break;
case 0xa:
*cursor++ = 'n';
break;
case 0xd:
*cursor++ = 'r';
break;
case 0x9:
*cursor++ = 't';
break;
default:
*cursor++ = 'u';
*cursor++ = '0';
*cursor++ = '0';
*cursor++ = hexdig(u >> 4);
*cursor++ = hexdig(u & 0xf);
}
} else {
*cursor++ = (uchar)u;
}
} else if (QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src,
end) < 0) {
// failed to get valid utf8 use JSON escape sequence
*cursor++ = '\\';
*cursor++ = 'u';
*cursor++ = hexdig(u >> 12 & 0x0f);
*cursor++ = hexdig(u >> 8 & 0x0f);
*cursor++ = hexdig(u >> 4 & 0x0f);
*cursor++ = hexdig(u & 0x0f);
}
}
ba.resize(cursor - reinterpret_cast<const uchar *>(ba.constData()));
return ba;
}
QJsonModel::QJsonModel(QObject *parent)
: QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
mHeaders.append(tr("key"));
mHeaders.append(tr("value"));
}
QJsonModel::QJsonModel(const QString &fileName, QObject *parent)
: QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
mHeaders.append(tr("key"));
mHeaders.append(tr("value"));
load(fileName);
}
QJsonModel::QJsonModel(QIODevice *device, QObject *parent)
: QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
mHeaders.append(tr("key"));
mHeaders.append(tr("value"));
load(device);
}
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent)
: QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
mHeaders.append(tr("key"));
mHeaders.append(tr("value"));
loadJson(json);
}
QJsonModel::~QJsonModel() { delete mRootItem; }
bool QJsonModel::load(const QString &fileName) {
QFile file(fileName);
bool success = false;
if (file.open(QIODevice::ReadOnly)) {
success = load(&file);
file.close();
} else {
success = false;
}
return success;
}
bool QJsonModel::load(QIODevice *device) { return loadJson(device->readAll()); }
bool QJsonModel::loadJson(const QByteArray &json) {
QJsonParseError error;
auto const &jdoc = QJsonDocument::fromJson(json, &error);
if (error.error != QJsonParseError::NoError) {
return false;
}
if (!jdoc.isNull()) {
beginResetModel();
delete mRootItem;
if (jdoc.isArray()) {
mRootItem =
QJsonTreeItem::load(QJsonValue(jdoc.array()), mExceptions);
mRootItem->setType(QJsonValue::Array);
} else {
mRootItem =
QJsonTreeItem::load(QJsonValue(jdoc.object()), mExceptions);
mRootItem->setType(QJsonValue::Object);
}
endResetModel();
return true;
}
qDebug() << Q_FUNC_INFO << "cannot load json";
return false;
}
QVariant QJsonModel::data(const QModelIndex &index, int role) const {
if (!index.isValid())
return {};
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
if (role == Qt::DisplayRole) {
if (index.column() == 0)
return QString("%1").arg(item->key());
if (index.column() == 1)
return item->value();
} else if (Qt::EditRole == role) {
if (index.column() == 1)
return item->value();
}
return {};
}
bool QJsonModel::setData(const QModelIndex &index, const QVariant &value,
int role) {
int col = index.column();
if (Qt::EditRole == role) {
if (col == 1) {
QJsonTreeItem *item =
static_cast<QJsonTreeItem *>(index.internalPointer());
item->setValue(value);
emit dataChanged(index, index, {Qt::EditRole});
return true;
}
}
return false;
}
QVariant QJsonModel::headerData(int section, Qt::Orientation orientation,
int role) const {
if (role != Qt::DisplayRole)
return {};
if (orientation == Qt::Horizontal)
return mHeaders.value(section);
else
return {};
}
QModelIndex QJsonModel::index(int row, int column,
const QModelIndex &parent) const {
if (!hasIndex(row, column, parent))
return {};
QJsonTreeItem *parentItem;
if (!parent.isValid())
parentItem = mRootItem;
else
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
QJsonTreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
else
return {};
}
QModelIndex QJsonModel::parent(const QModelIndex &index) const {
if (!index.isValid())
return {};
QJsonTreeItem *childItem =
static_cast<QJsonTreeItem *>(index.internalPointer());
QJsonTreeItem *parentItem = childItem->parent();
if (parentItem == mRootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
int QJsonModel::rowCount(const QModelIndex &parent) const {
QJsonTreeItem *parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parentItem = mRootItem;
else
parentItem = static_cast<QJsonTreeItem *>(parent.internalPointer());
return parentItem->childCount();
}
int QJsonModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent)
return 2;
}
Qt::ItemFlags QJsonModel::flags(const QModelIndex &index) const {
int col = index.column();
auto item = static_cast<QJsonTreeItem *>(index.internalPointer());
auto isArray = QJsonValue::Array == item->type();
auto isObject = QJsonValue::Object == item->type();
if ((col == 1) && !(isArray || isObject))
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
else
return QAbstractItemModel::flags(index);
}
QByteArray QJsonModel::json(bool compact) {
auto jsonValue = genJson(mRootItem);
QByteArray json;
if (jsonValue.isNull())
return json;
if (jsonValue.isArray())
arrayToJson(jsonValue.toArray(), json, 0, compact);
else
objectToJson(jsonValue.toObject(), json, 0, compact);
return json;
}
void QJsonModel::objectToJson(QJsonObject jsonObject, QByteArray &json,
int indent, bool compact) {
json += compact ? "{" : "{\n";
objectContentToJson(jsonObject, json, indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += compact ? "}" : "}\n";
}
void QJsonModel::arrayToJson(QJsonArray jsonArray, QByteArray &json, int indent,
bool compact) {
json += compact ? "[" : "[\n";
arrayContentToJson(jsonArray, json, indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += compact ? "]" : "]\n";
}
void QJsonModel::arrayContentToJson(QJsonArray jsonArray, QByteArray &json,
int indent, bool compact) {
if (jsonArray.size() <= 0)
return;
QByteArray indentString(4 * indent, ' ');
int i = 0;
while (1) {
json += indentString;
valueToJson(jsonArray.at(i), json, indent, compact);
if (++i == jsonArray.size()) {
if (!compact)
json += '\n';
break;
}
json += compact ? "," : ",\n";
}
}
void QJsonModel::objectContentToJson(QJsonObject jsonObject, QByteArray &json,
int indent, bool compact) {
if (jsonObject.size() <= 0)
return;
QByteArray indentString(4 * indent, ' ');
int i = 0;
while (1) {
QString key = jsonObject.keys().at(i);
json += indentString;
json += '"';
json += escapedString(key);
json += compact ? "\":" : "\": ";
valueToJson(jsonObject.value(key), json, indent, compact);
if (++i == jsonObject.size()) {
if (!compact)
json += '\n';
break;
}
json += compact ? "," : ",\n";
}
}
void QJsonModel::valueToJson(QJsonValue jsonValue, QByteArray &json, int indent,
bool compact) {
QJsonValue::Type type = jsonValue.type();
switch (type) {
case QJsonValue::Bool:
json += jsonValue.toBool() ? "true" : "false";
break;
case QJsonValue::Double: {
const double d = jsonValue.toDouble();
if (qIsFinite(d)) {
json += QByteArray::number(d, 'f', QLocale::FloatingPointShortest);
} else {
json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4)
}
break;
}
case QJsonValue::String:
json += '"';
json += escapedString(jsonValue.toString());
json += '"';
break;
case QJsonValue::Array:
json += compact ? "[" : "[\n";
arrayContentToJson(jsonValue.toArray(), json,
indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += ']';
break;
case QJsonValue::Object:
json += compact ? "{" : "{\n";
objectContentToJson(jsonValue.toObject(), json,
indent + (compact ? 0 : 1), compact);
json += QByteArray(4 * indent, ' ');
json += '}';
break;
case QJsonValue::Null:
default:
json += "null";
}
}
void QJsonModel::addException(const QStringList &exceptions) {
mExceptions = exceptions;
}
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const {
auto type = item->type();
int nchild = item->childCount();
if (QJsonValue::Object == type) {
QJsonObject jo;
for (int i = 0; i < nchild; ++i) {
auto ch = item->child(i);
auto key = ch->key();
jo.insert(key, genJson(ch));
}
return jo;
} else if (QJsonValue::Array == type) {
QJsonArray arr;
for (int i = 0; i < nchild; ++i) {
auto ch = item->child(i);
arr.append(genJson(ch));
}
return arr;
} else {
QJsonValue va;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
switch (item->value().typeId()) {
#else
switch (item->value().userType()) {
#endif
case QMetaType::Bool: {
va = item->value().toBool();
break;
}
default:
va = item->value().toString();
break;
}
return va;
}
}

View File

@ -1,56 +0,0 @@
# QJsonModel
QJsonModel is a JSON tree model class for Qt6/C++17 based on QAbstractItemModel.
QJsonModel was originally written by Sacha Shutz (https://github.com/dridk).
This fork is also released under the MIT License.
![QJsonModel](https://gitea.beniquez.me/sdaveb/QJsonModel/raw/branch/master/screen.png)
## Build Instructions
### Build Tools
- CMake (version 3.21 or higher)
- C++17-compatible compiler
### Building the Project
1. Clone the repository:
```
git clone <URL>
```
2. Navigate to the project directory:
```
cd elemental-game
```
3. Configure your build system:
```bash
cmake -B debug -G Unix Makefiles
# or
cmake -B debug -G Ninja # this is faster and more modern
```
4. Invoke your build system
```
cmake --build debug
```
### Usage - CMake
You can add this library to your CMake projects using FetchContent()
or CPM_AddPackage().
Here's how to do it with CPM_AddPackage:
```
COMING SOON
```
### Usage - C++
####
```cpp
QJsonModel * model = new QJsonModel;
QTreeView * view = new QTreeView;
view->setModel(model);
model->load("example.json")
```

View File

@ -1,115 +0,0 @@
/* QJsonModel.hpp
* Copyright (c) 2011 SCHUTZ Sacha
* Copyright © 2024 Saul D. Beniquez
*
* License:
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <QAbstractItemModel>
#include <QIcon>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include "details/QUtf8.hpp"
class QJsonModel;
class QJsonItem;
class QJsonTreeItem {
public:
QJsonTreeItem(QJsonTreeItem *parent = nullptr);
~QJsonTreeItem();
void appendChild(QJsonTreeItem *item);
QJsonTreeItem *child(int row);
QJsonTreeItem *parent();
int childCount() const;
int row() const;
void setKey(const QString &key);
void setValue(const QVariant &value);
void setType(const QJsonValue::Type &type);
QString key() const;
QVariant value() const;
QJsonValue::Type type() const;
static QJsonTreeItem *load(const QJsonValue &value,
const QStringList &exceptions = {},
QJsonTreeItem *parent = nullptr);
protected:
private:
QString mKey;
QVariant mValue;
QJsonValue::Type mType;
QList<QJsonTreeItem *> mChilds;
QJsonTreeItem *mParent = nullptr;
};
//---------------------------------------------------
class QJsonModel : public QAbstractItemModel {
Q_OBJECT
public:
explicit QJsonModel(QObject *parent = nullptr);
QJsonModel(const QString &fileName, QObject *parent = nullptr);
QJsonModel(QIODevice *device, QObject *parent = nullptr);
QJsonModel(const QByteArray &json, QObject *parent = nullptr);
~QJsonModel();
bool load(const QString &fileName);
bool load(QIODevice *device);
bool loadJson(const QByteArray &json);
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override;
QVariant headerData(int section, Qt::Orientation orientation,
int role) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QByteArray json(bool compact = false);
QByteArray jsonToByte(QJsonValue jsonValue);
void objectToJson(QJsonObject jsonObject, QByteArray &json, int indent,
bool compact);
void arrayToJson(QJsonArray jsonArray, QByteArray &json, int indent,
bool compact);
void arrayContentToJson(QJsonArray jsonArray, QByteArray &json, int indent,
bool compact);
void objectContentToJson(QJsonObject jsonObject, QByteArray &json,
int indent, bool compact);
void valueToJson(QJsonValue jsonValue, QByteArray &json, int indent,
bool compact);
//! List of tags to skip during JSON parsing
void addException(const QStringList &exceptions);
private:
QJsonValue genJson(QJsonTreeItem *) const;
QJsonTreeItem *mRootItem = nullptr;
QStringList mHeaders;
//! List of exceptions (e.g. comments). Case insensitive, compairs on
//! "contains".
QStringList mExceptions;
};

View File

@ -1,194 +0,0 @@
/* QUtf8.hpp
* Copyright © 2024 Saul D. Beniquez
* License:
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <QJsonValue>
namespace QUtf8Functions {
/// returns 0 on success; errors can only happen if \a u is a surrogate:
/// Error if \a u is a low surrogate;
/// if \a u is a high surrogate, Error if the next isn't a low one,
/// EndOfString if we run into the end of the string.
template <typename Traits, typename OutputPtr, typename InputPtr>
inline int toUtf8(ushort u, OutputPtr &dst, InputPtr &src, InputPtr end) {
if (!Traits::skipAsciiHandling && u < 0x80) {
// U+0000 to U+007F (US-ASCII) - one byte
Traits::appendByte(dst, uchar(u));
return 0;
} else if (u < 0x0800) {
// U+0080 to U+07FF - two bytes
// first of two bytes
Traits::appendByte(dst, 0xc0 | uchar(u >> 6));
} else {
if (!QChar::isSurrogate(u)) {
// U+0800 to U+FFFF (except U+D800-U+DFFF) - three bytes
if (!Traits::allowNonCharacters && QChar::isNonCharacter(u))
return Traits::Error;
// first of three bytes
Traits::appendByte(dst, 0xe0 | uchar(u >> 12));
} else {
// U+10000 to U+10FFFF - four bytes
// need to get one extra codepoint
if (Traits::availableUtf16(src, end) == 0)
return Traits::EndOfString;
ushort low = Traits::peekUtf16(src);
if (!QChar::isHighSurrogate(u))
return Traits::Error;
if (!QChar::isLowSurrogate(low))
return Traits::Error;
Traits::advanceUtf16(src);
uint ucs4 = QChar::surrogateToUcs4(u, low);
if (!Traits::allowNonCharacters && QChar::isNonCharacter(ucs4))
return Traits::Error;
// first byte
Traits::appendByte(dst, 0xf0 | (uchar(ucs4 >> 18) & 0xf));
// second of four bytes
Traits::appendByte(dst, 0x80 | (uchar(ucs4 >> 12) & 0x3f));
// for the rest of the bytes
u = ushort(ucs4);
}
// second to last byte
Traits::appendByte(dst, 0x80 | (uchar(u >> 6) & 0x3f));
}
// last byte
Traits::appendByte(dst, 0x80 | (u & 0x3f));
return 0;
}
inline bool isContinuationByte(uchar b) { return (b & 0xc0) == 0x80; }
/// returns the number of characters consumed (including \a b) in case of
/// success; returns negative in case of error: Traits::Error or
/// Traits::EndOfString
template <typename Traits, typename OutputPtr, typename InputPtr>
inline int fromUtf8(uchar b, OutputPtr &dst, InputPtr &src, InputPtr end) {
int charsNeeded;
uint min_uc;
uint uc;
if (!Traits::skipAsciiHandling && b < 0x80) {
// US-ASCII
Traits::appendUtf16(dst, b);
return 1;
}
if (!Traits::isTrusted && Q_UNLIKELY(b <= 0xC1)) {
// an UTF-8 first character must be at least 0xC0
// however, all 0xC0 and 0xC1 first bytes can only produce overlong
// sequences
return Traits::Error;
} else if (b < 0xe0) {
charsNeeded = 2;
min_uc = 0x80;
uc = b & 0x1f;
} else if (b < 0xf0) {
charsNeeded = 3;
min_uc = 0x800;
uc = b & 0x0f;
} else if (b < 0xf5) {
charsNeeded = 4;
min_uc = 0x10000;
uc = b & 0x07;
} else {
// the last Unicode character is U+10FFFF
// it's encoded in UTF-8 as "\xF4\x8F\xBF\xBF"
// therefore, a byte higher than 0xF4 is not the UTF-8 first byte
return Traits::Error;
}
int bytesAvailable = Traits::availableBytes(src, end);
if (Q_UNLIKELY(bytesAvailable < charsNeeded - 1)) {
// it's possible that we have an error instead of just unfinished bytes
if (bytesAvailable > 0 && !isContinuationByte(Traits::peekByte(src, 0)))
return Traits::Error;
if (bytesAvailable > 1 && !isContinuationByte(Traits::peekByte(src, 1)))
return Traits::Error;
return Traits::EndOfString;
}
// first continuation character
b = Traits::peekByte(src, 0);
if (!isContinuationByte(b))
return Traits::Error;
uc <<= 6;
uc |= b & 0x3f;
if (charsNeeded > 2) {
// second continuation character
b = Traits::peekByte(src, 1);
if (!isContinuationByte(b))
return Traits::Error;
uc <<= 6;
uc |= b & 0x3f;
if (charsNeeded > 3) {
// third continuation character
b = Traits::peekByte(src, 2);
if (!isContinuationByte(b))
return Traits::Error;
uc <<= 6;
uc |= b & 0x3f;
}
}
// we've decoded something; safety-check it
if (!Traits::isTrusted) {
if (uc < min_uc)
return Traits::Error;
if (QChar::isSurrogate(uc) || uc > QChar::LastValidCodePoint)
return Traits::Error;
if (!Traits::allowNonCharacters && QChar::isNonCharacter(uc))
return Traits::Error;
}
// write the UTF-16 sequence
if (!QChar::requiresSurrogates(uc)) {
// UTF-8 decoded and no surrogates are required
// detach if necessary
Traits::appendUtf16(dst, ushort(uc));
} else {
// UTF-8 decoded to something that requires a surrogate pair
Traits::appendUcs4(dst, uc);
}
Traits::advanceByte(src, charsNeeded - 1);
return charsNeeded;
}
} // namespace QUtf8Functions
struct QUtf8BaseTraits {
static const bool isTrusted = false;
static const bool allowNonCharacters = true;
static const bool skipAsciiHandling = false;
static const int Error = -1;
static const int EndOfString = -2;
static bool isValidCharacter(uint u) { return int(u) >= 0; }
static void appendByte(uchar *&ptr, uchar b) { *ptr++ = b; }
static uchar peekByte(const uchar *ptr, int n = 0) { return ptr[n]; }
static qptrdiff availableBytes(const uchar *ptr, const uchar *end) {
return end - ptr;
}
static void advanceByte(const uchar *&ptr, int n = 1) { ptr += n; }
static void appendUtf16(ushort *&ptr, ushort uc) { *ptr++ = uc; }
static void appendUcs4(ushort *&ptr, uint uc) {
appendUtf16(ptr, QChar::highSurrogate(uc));
appendUtf16(ptr, QChar::lowSurrogate(uc));
}
static ushort peekUtf16(const ushort *ptr, int n = 0) { return ptr[n]; }
static qptrdiff availableUtf16(const ushort *ptr, const ushort *end) {
return end - ptr;
}
static void advanceUtf16(const ushort *&ptr, int n = 1) { ptr += n; }
// it's possible to output to UCS-4 too
static void appendUtf16(uint *&ptr, ushort uc) { *ptr++ = uc; }
static void appendUcs4(uint *&ptr, uint uc) { *ptr++ = uc; }
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

@ -1 +1 @@
Subproject commit fe0774c1d2ff5c86832d5850c1dccbbf3a6c3c66 Subproject commit 3a5bb0d8bc45b6150ed4a7513b0712b0a5954a74

2
3rdparty/cpptrace vendored

@ -1 +1 @@
Subproject commit fac4d08fd0473a94d99c143c6ba6b1f9e0bd7636 Subproject commit ce639ebfcec47a7c74233b4bab50017cb34e615b

View File

@ -33,7 +33,8 @@ QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
#endif #endif
prefix = id.section(QLatin1Char('/'), -1); prefix = id.section(QLatin1Char('/'), -1);
} }
prefix.remove(QRegularExpression("[^a-zA-Z]")); static QRegularExpression regex("[^a-zA-Z]");
prefix.remove(regex);
prefix.truncate(6); prefix.truncate(6);
QByteArray idc = id.toUtf8(); QByteArray idc = id.toUtf8();
@ -69,6 +70,8 @@ QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId)
lockFile.open(QIODevice::ReadWrite); lockFile.open(QIODevice::ReadWrite);
} }
QtLocalPeer::~QtLocalPeer() { server->close(); }
bool QtLocalPeer::isClient() { bool QtLocalPeer::isClient() {
if (lockFile.isLocked()) if (lockFile.isLocked())
return false; return false;

View File

@ -15,6 +15,8 @@ class QtLocalPeer : public QObject {
public: public:
QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString()); QtLocalPeer(QObject *parent = nullptr, const QString &appId = QString());
~QtLocalPeer();
bool isClient(); bool isClient();
bool sendMessage(const QByteArray &uMsg, int timeout); bool sendMessage(const QByteArray &uMsg, int timeout);
QString applicationId() const { return id; } QString applicationId() const { return id; }

View File

@ -8,7 +8,7 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJECT_VERSION "2.2.1") set(PROJECT_VERSION "2.2.3")
find_package( find_package(
QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network Concurrent QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network Concurrent
@ -21,12 +21,16 @@ message("Build ${PROJECT_NAME} with ${CMAKE_BUILD_TYPE}.")
install(CODE "set(CMAKE_INSTALL_LOCAL_ONLY TRUE)" ALL_COMPONENTS) install(CODE "set(CMAKE_INSTALL_LOCAL_ONLY TRUE)" ALL_COMPONENTS)
option(WINGHEX_USE_FRAMELESS ON)
option(BUILD_TEST_PLUGIN OFF) option(BUILD_TEST_PLUGIN OFF)
option(BUILD_SHARED_MEM_EXT OFF)
add_definitions(-DAS_NO_THREADS)
if(BUILD_TEST_PLUGIN) if(BUILD_TEST_PLUGIN)
add_subdirectory(TestPlugin) add_subdirectory(TestPlugin)
endif() endif()
option(BUILD_SHARED_MEM_EXT OFF)
if(BUILD_SHARED_MEM_EXT) if(BUILD_SHARED_MEM_EXT)
add_subdirectory(ShareMemoryDrv) add_subdirectory(ShareMemoryDrv)
endif() endif()
@ -36,13 +40,10 @@ add_definitions(-DWINGHEX_VERSION="${PROJECT_VERSION}"
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WINGHEX_VERSION" ${PROJECT_VERSION}) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/WINGHEX_VERSION" ${PROJECT_VERSION})
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/QT_VERSION" ${QT_VERSION_MAJOR}) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/QT_VERSION" ${QT_VERSION_MAJOR})
option(WINGHEX_USE_FRAMELESS "Use borderless windows to ensure UI uniformity"
TRUE)
if(WIN32) if(WIN32)
find_package(QT NAMES Qt6 Qt5 REQUIRED AxContainer) find_package(QT NAMES Qt6 Qt5 REQUIRED AxContainer)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED AxContainer) find_package(Qt${QT_VERSION_MAJOR} REQUIRED AxContainer)
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) add_definitions(-DNOMINMAX)
endif() endif()
if(${QT_VERSION_MAJOR} EQUAL 5) if(${QT_VERSION_MAJOR} EQUAL 5)
@ -66,7 +67,7 @@ if(WINGHEX_USE_FRAMELESS)
option(QWINDOWKIT_BUILD_STATIC "Build static libraries" TRUE) option(QWINDOWKIT_BUILD_STATIC "Build static libraries" TRUE)
option(QWINDOWKIT_INSTALL "Install library" OFF) option(QWINDOWKIT_INSTALL "Install library" OFF)
add_subdirectory(3rdparty/qwindowkit) add_subdirectory(3rdparty/qwindowkit)
add_definitions(-DWINGHEX_USE_FRAMELESS) add_compile_definitions(WINGHEX_USE_FRAMELESS)
endif() endif()
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
@ -79,7 +80,6 @@ add_subdirectory(3rdparty/QHexView)
add_subdirectory(3rdparty/WingCodeEdit) add_subdirectory(3rdparty/WingCodeEdit)
add_subdirectory(3rdparty/Qt-Advanced-Docking-System) add_subdirectory(3rdparty/Qt-Advanced-Docking-System)
add_subdirectory(3rdparty/AngelScript/sdk/angelscript/projects/cmake) add_subdirectory(3rdparty/AngelScript/sdk/angelscript/projects/cmake)
add_subdirectory(3rdparty/QJsonModel)
set(ANGEL_SCRIPT_ADDON_ROOT set(ANGEL_SCRIPT_ADDON_ROOT
"${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/AngelScript/sdk/add_on") "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/AngelScript/sdk/add_on")
@ -194,8 +194,6 @@ set(CONTROL_SRC
src/control/qlistviewext.cpp src/control/qlistviewext.cpp
src/control/asobjtreewidget.h src/control/asobjtreewidget.h
src/control/asobjtreewidget.cpp src/control/asobjtreewidget.cpp
src/control/qtlonglongspinbox.cpp
src/control/qtlonglongspinbox.h
src/control/dockwidgettab.h src/control/dockwidgettab.h
src/control/dockwidgettab.cpp src/control/dockwidgettab.cpp
src/control/qhextextedit.h src/control/qhextextedit.h
@ -209,7 +207,9 @@ set(CONTROL_SRC
src/control/gotolinewidget.h src/control/gotolinewidget.h
src/control/gotolinewidget.cpp src/control/gotolinewidget.cpp
src/control/codeeditcontrolwidget.h src/control/codeeditcontrolwidget.h
src/control/codeeditcontrolwidget.cpp) src/control/codeeditcontrolwidget.cpp
src/control/scrollablelabel.h
src/control/scrollablelabel.cpp)
set(CLASS_SRC set(CLASS_SRC
src/class/logger.cpp src/class/logger.cpp
@ -239,8 +239,6 @@ set(CLASS_SRC
src/class/settingmanager.cpp src/class/settingmanager.cpp
src/class/asdebugger.h src/class/asdebugger.h
src/class/asdebugger.cpp src/class/asdebugger.cpp
src/class/scriptconsolemachine.h
src/class/scriptconsolemachine.cpp
src/class/angelobjstring.h src/class/angelobjstring.h
src/class/angelobjstring.cpp src/class/angelobjstring.cpp
src/class/scripteditortheme.h src/class/scripteditortheme.h
@ -256,8 +254,6 @@ set(CLASS_SRC
src/class/ascompletion.h src/class/ascompletion.h
src/class/asbuilder.h src/class/asbuilder.h
src/class/asbuilder.cpp src/class/asbuilder.cpp
src/class/ascontextmgr.h
src/class/ascontextmgr.cpp
src/class/clangformatmanager.h src/class/clangformatmanager.h
src/class/clangformatmanager.cpp src/class/clangformatmanager.cpp
src/class/aspreprocesser.h src/class/aspreprocesser.h
@ -274,7 +270,6 @@ set(CLASS_SRC
src/class/dockcomponentsfactory.cpp src/class/dockcomponentsfactory.cpp
src/class/diffutil.h src/class/diffutil.h
src/class/diffutil.cpp src/class/diffutil.cpp
src/class/clickcallback.h
src/class/crashhandler.h src/class/crashhandler.h
src/class/crashhandler.cpp src/class/crashhandler.cpp
src/class/pluginsystem.h src/class/pluginsystem.h
@ -317,10 +312,6 @@ set(MODEL_SRC
src/model/metadatamodel.cpp src/model/metadatamodel.cpp
src/model/checksummodel.h src/model/checksummodel.h
src/model/checksummodel.cpp src/model/checksummodel.cpp
src/model/qjsontablemodel.h
src/model/qjsontablemodel.cpp
src/model/scriptobjmodel.h
src/model/scriptobjmodel.cpp
src/model/dbgcallstackmodel.h src/model/dbgcallstackmodel.h
src/model/dbgcallstackmodel.cpp src/model/dbgcallstackmodel.cpp
src/model/dbgvarshowmodel.h src/model/dbgvarshowmodel.h
@ -364,7 +355,8 @@ set(SCRIPT_ADDON_SRC
src/scriptaddon/scriptjson.h src/scriptaddon/scriptjson.h
src/scriptaddon/scriptjson.cpp src/scriptaddon/scriptjson.cpp
src/scriptaddon/scriptfile.cpp src/scriptaddon/scriptfile.cpp
src/scriptaddon/scriptfile.h) src/scriptaddon/scriptfile.h
src/scriptaddon/aspromise.hpp)
# localization support # localization support
file( file(
@ -384,7 +376,6 @@ endforeach()
set(TRANSLATION_PATH set(TRANSLATION_PATH
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QConsoleWidget ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QConsoleWidget
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QHexView ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QHexView
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QJsonModel
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/Qt-Advanced-Docking-System/src ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/Qt-Advanced-Docking-System/src
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QWingRibbon ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/QWingRibbon
${CMAKE_CURRENT_SOURCE_DIR}/src) ${CMAKE_CURRENT_SOURCE_DIR}/src)
@ -518,7 +509,6 @@ target_link_libraries(
WingPlugin WingPlugin
QHexView QHexView
WingCodeEdit WingCodeEdit
QJsonModel
angelscript angelscript
qtadvanceddocking-qt${QT_VERSION_MAJOR}) qtadvanceddocking-qt${QT_VERSION_MAJOR})

View File

@ -115,8 +115,7 @@
1. 本软件源代码不得私自应用于闭源商业用途除非你完整开源GPL协议的要求。如果要将软件仓库的代码商用闭源必须找我购买商业授权签订合同价格私聊非诚勿扰。 1. 本软件源代码不得私自应用于闭源商业用途除非你完整开源GPL协议的要求。如果要将软件仓库的代码商用闭源必须找我购买商业授权签订合同价格私聊非诚勿扰。
2. 本软件是用我的业余时间编写,不能及时修复 Bug 或者提供技术支持,请见谅。 2. 本软件是用我的业余时间编写,不能及时修复 Bug 或者提供技术支持,请见谅。
3. 本人非计算机专业,编写程序难免有 Bug ,欢迎提交 PR 。 3. 无论在什么时候有疑问,请详细阅读 Wiki 。
4. 无论在什么时候有疑问,请详细阅读 Wiki 。
### 打包者必读 ### 打包者必读
@ -128,7 +127,7 @@
4. 包内最好含有主程序的校验和,但不强求。 4. 包内最好含有主程序的校验和,但不强求。
5. 无论是哪种打包形式,都一定要声明其开源协议和自由属性,不得隐藏而借机收费。虽然收费我并不反感,下载服务器还是需要资金维护的,但借着信息差骗人收费,这是我极其深恶痛绝的。 5. 无论是哪种打包形式,都一定要声明其开源协议和自由属性,不得隐藏而借机收费。虽然收费我并不反感,下载服务器还是需要资金维护的,但借着信息差骗人收费,这是我极其深恶痛绝的。
6. 无论以任何为目的,如未获得我作者的授权,不得修改任意程序内指向的网络链接和软件关于信息,比如赞助和关于软件部分的内容等。 6. 无论以任何为目的,如未获得我作者的授权,不得修改任意程序内指向的网络链接和软件关于信息,比如赞助和关于软件部分的内容等。
7. 不得在安装程序内插入任何含有商业推广的插件,并且严格遵守第二条内容 7. 不得在安装程序内插入任何含有商业推广的插件。
### issue 前必读 ### issue 前必读
@ -174,7 +173,7 @@
## WIKI ## WIKI
&emsp;&emsp;如果想学习羽云十六进制编辑器的使用以及如何开发该软件的插件,请到 [该链接](https://github.com/Wing-summer/WingHexExplorer2/wiki/%E7%AE%80%E4%BB%8B) ,同时也欢迎大家指出 Wiki 的错误以及贡献优质内容。 &emsp;&emsp;如果想学习羽云十六进制编辑器的使用以及如何开发该软件的插件,请到 [该链接](https://wing-summer.github.io/WingHexExplorer2/docs/zh/credits.html) ,同时也欢迎大家指出 Wiki 的错误以及贡献优质内容。
## 插件库 ## 插件库

View File

@ -115,8 +115,7 @@ For plugin development, the corresponding open source agreements are different.
1. The source code of this software shall not be used for closed-source commercial purposes unless you open source it completely (as required by the GPL agreement). If you want to commercially close the code of the software warehouse, you must contact me to purchase a commercial license and sign a contract. Please contact me for the price. Please do not disturb me if you are not serious. 1. The source code of this software shall not be used for closed-source commercial purposes unless you open source it completely (as required by the GPL agreement). If you want to commercially close the code of the software warehouse, you must contact me to purchase a commercial license and sign a contract. Please contact me for the price. Please do not disturb me if you are not serious.
2. This software was written in my spare time. Please forgive me for not being able to fix bugs or provide technical support in time. 2. This software was written in my spare time. Please forgive me for not being able to fix bugs or provide technical support in time.
3. I am not a computer major, and there are inevitably bugs in the program I write. Welcome to submit PR. 3. Whenever you have questions, please read the Wiki in detail.
4. Whenever you have questions, please read the Wiki in detail.
### For Packagers ### For Packagers
@ -128,7 +127,7 @@ First of all, I would like to express my sincere tanks for your enthusiastic hel
4. It is best to contain the checksum of the main program in the package, but it is not mandatory. 4. It is best to contain the checksum of the main program in the package, but it is not mandatory.
5. Regardless of the packaging format, its open source agreement and free attributes must be stated, and it is not allowed to hide and charge for it. Although I don't mind charging, the download server still needs money to maintain, but I hate charging by taking advantage of the information gap. 5. Regardless of the packaging format, its open source agreement and free attributes must be stated, and it is not allowed to hide and charge for it. Although I don't mind charging, the download server still needs money to maintain, but I hate charging by taking advantage of the information gap.
6. Regardless of the purpose, if you do not obtain the authorization of me, you may not modify any network links pointed to and the ABOUT contents in the program, such as sponsorship and content about the software. 6. Regardless of the purpose, if you do not obtain the authorization of me, you may not modify any network links pointed to and the ABOUT contents in the program, such as sponsorship and content about the software.
7. You may not insert any plug-in containing commercial promotion in the installation program, and strictly abide by the content of the second article. 7. You may not insert any plug-in containing commercial promotion in the installation program.
### Issue ### Issue
@ -175,7 +174,7 @@ Of course, there are other repositories as mirror for Chinese users (which will
## WIKI ## WIKI
&emsp;&emsp;If you want to learn how to use WingHexEditor and how to develop plug-ins for the software, please go to this link: `Not available yet`. At the same time, you are also welcome to point out errors in the Wiki and contribute high-quality content. &emsp;&emsp;If you want to learn how to use WingHexEditor and how to develop plug-ins for the software, please go to [this link](https://wing-summer.github.io/WingHexExplorer2/docs/zh/credits.html) (Chinese only). At the same time, you are also welcome to point out errors in the Wiki and contribute high-quality content.
## Plugins ## Plugins

View File

@ -61,8 +61,6 @@ add_library(
ctltestform.h ctltestform.h
ctltestform.cpp ctltestform.cpp
ctltestform.ui ctltestform.ui
testtablemodel.h
testtablemodel.cpp
testsettingpage.h testsettingpage.h
testsettingpage.cpp testsettingpage.cpp
testwingeditorviewwidget.h testwingeditorviewwidget.h
@ -91,4 +89,5 @@ if(TEST_MODE)
${WINGHEX_PLUGIN_PATH}) ${WINGHEX_PLUGIN_PATH})
endif() endif()
target_link_libraries(TestPlugin PRIVATE Qt${QT_VERSION_MAJOR}::Widgets WingPlugin) target_link_libraries(TestPlugin PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
WingPlugin)

View File

@ -4,7 +4,7 @@
# You can redistribute this file and/or modify it under the terms of the BSD # You can redistribute this file and/or modify it under the terms of the BSD
# 3-Clause. # 3-Clause.
# #
# THIS FILE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND # THIS FILE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE

View File

@ -185,12 +185,12 @@
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.ui" line="1184"/> <location filename="../testform.ui" line="1055"/>
<source>Others</source> <source>Others</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../testform.ui" line="1245"/> <location filename="../testform.ui" line="1116"/>
<source>Other APIs should be Test With Script</source> <source>Other APIs should be Test With Script</source>
<translation> API </translation> <translation> API </translation>
</message> </message>
@ -231,7 +231,6 @@
<location filename="../testform.ui" line="311"/> <location filename="../testform.ui" line="311"/>
<location filename="../testform.ui" line="707"/> <location filename="../testform.ui" line="707"/>
<location filename="../testform.ui" line="881"/> <location filename="../testform.ui" line="881"/>
<location filename="../testform.ui" line="1070"/>
<source>Type</source> <source>Type</source>
<translation></translation> <translation></translation>
</message> </message>
@ -266,32 +265,6 @@
<source>Color</source> <source>Color</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<location filename="../testform.ui" line="1055"/>
<source>DataVisual</source>
<translation></translation>
</message>
<message>
<location filename="../testform.cpp" line="340"/>
<location filename="../testform.cpp" line="349"/>
<source>UpdateTextTreeError</source>
<translation></translation>
</message>
<message>
<location filename="../testform.cpp" line="364"/>
<source>UpdateTextListByModelError</source>
<translation></translation>
</message>
<message>
<location filename="../testform.cpp" line="374"/>
<source>UpdateTextTableByModelError</source>
<translation></translation>
</message>
<message>
<location filename="../testform.cpp" line="385"/>
<source>UpdateTextTreeByModelError</source>
<translation></translation>
</message>
</context> </context>
<context> <context>
<name>TestPlugin</name> <name>TestPlugin</name>

View File

@ -24,7 +24,6 @@
#include "ctltestform.h" #include "ctltestform.h"
#include "readertestform.h" #include "readertestform.h"
#include "testtablemodel.h"
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QFileSystemModel> #include <QFileSystemModel>
@ -37,8 +36,6 @@ TestForm::TestForm(WingHex::IWingPlugin *plg, QWidget *parent)
: WingHex::WingPluginWidget(plg, parent), ui(new Ui::TestForm) { : WingHex::WingPluginWidget(plg, parent), ui(new Ui::TestForm) {
ui->setupUi(this); ui->setupUi(this);
ui->teDataVisual->setAcceptRichText(false);
ui->saReader->widget()->layout()->addWidget( ui->saReader->widget()->layout()->addWidget(
new ReaderTestForm(plg, ui->tbReaderLogger, this)); new ReaderTestForm(plg, ui->tbReaderLogger, this));
ui->saCtl->widget()->layout()->addWidget( ui->saCtl->widget()->layout()->addWidget(
@ -56,10 +53,6 @@ TestForm::TestForm(WingHex::IWingPlugin *plg, QWidget *parent)
ui->lblauthor->setPixmap( ui->lblauthor->setPixmap(
WingHex::HOSTRESPIMG(QStringLiteral("author"), QStringLiteral(".jpg"))); WingHex::HOSTRESPIMG(QStringLiteral("author"), QStringLiteral(".jpg")));
_click = std::bind(&TestForm::onDVClicked, this, std::placeholders::_1);
_dblclick =
std::bind(&TestForm::onDVDoubleClicked, this, std::placeholders::_1);
} }
TestForm::~TestForm() { delete ui; } TestForm::~TestForm() { delete ui; }
@ -153,16 +146,6 @@ QFileDialog::Options TestForm::getFileDialogOptions() const {
return options; return options;
} }
void TestForm::onDVClicked(const QModelIndex &index) {
logWarn(QStringLiteral("[Test - Click] ") +
index.model()->data(index).toString());
}
void TestForm::onDVDoubleClicked(const QModelIndex &index) {
msgWarning(this, QStringLiteral("Test - DoubleClick"),
index.model()->data(index).toString());
}
void TestForm::on_btnSendLog_clicked() { void TestForm::on_btnSendLog_clicked() {
auto txt = ui->leLogText->text(); auto txt = ui->leLogText->text();
switch (Level(ui->cbLogLevel->currentIndex())) { switch (Level(ui->cbLogLevel->currentIndex())) {
@ -323,69 +306,6 @@ void TestForm::on_btnGetColor_clicked() {
} }
} }
void TestForm::on_btnText_2_clicked() {
dataVisualText(ui->teDataVisual->toPlainText(), QStringLiteral("TestForm"));
}
void TestForm::on_btnTextList_clicked() {
auto txts = ui->teDataVisual->toPlainText().split('\n');
dataVisualTextList(txts, QStringLiteral("TestForm"), _click, _dblclick);
}
void TestForm::on_btnTextTree_clicked() {
auto ret =
dataVisualTextTree(ui->teDataVisual->toPlainText(),
QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) {
msgCritical(this, QStringLiteral("Test"), tr("UpdateTextTreeError"));
}
}
void TestForm::on_btnTextTable_clicked() {
auto ret = dataVisualTextTable(
ui->teDataVisual->toPlainText(), {"wingsummer", "wingsummer"}, {},
QStringLiteral("TestForm"), _click, _dblclick);
if (!ret) {
msgCritical(this, QStringLiteral("Test"), tr("UpdateTextTreeError"));
}
}
void TestForm::on_btnTextListByModel_clicked() {
auto model = new QStringListModel;
QStringList buffer;
for (int i = 0; i < WingHex::SDKVERSION; ++i) {
buffer.append("wingsummer" % QString::number(i));
}
model->setStringList(buffer);
auto ret = dataVisualTextListByModel(model, QStringLiteral("TestForm"),
_click, _dblclick);
if (!ret) {
msgCritical(this, QStringLiteral("Test"),
tr("UpdateTextListByModelError"));
}
}
void TestForm::on_btnTextTableByModel_clicked() {
auto model = new TestTableModel;
auto ret = dataVisualTextTableByModel(model, QStringLiteral("TestForm"),
_click, _dblclick);
if (!ret) {
msgCritical(this, QStringLiteral("Test"),
tr("UpdateTextTableByModelError"));
}
}
void TestForm::on_btnTextTreeByModel_clicked() {
auto model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());
auto ret = dataVisualTextTreeByModel(model, QStringLiteral("TestForm"),
_click, _dblclick);
if (!ret) {
msgCritical(this, QStringLiteral("Test"),
tr("UpdateTextTreeByModelError"));
}
}
void TestForm::on_btnStatusVisible_clicked() { void TestForm::on_btnStatusVisible_clicked() {
if (ui->rbLockedFile->isChecked()) { if (ui->rbLockedFile->isChecked()) {
Q_UNUSED(setLockedFile(true)); Q_UNUSED(setLockedFile(true));

View File

@ -85,20 +85,6 @@ private slots:
void on_btnGetColor_clicked(); void on_btnGetColor_clicked();
void on_btnText_2_clicked();
void on_btnTextList_clicked();
void on_btnTextTree_clicked();
void on_btnTextTable_clicked();
void on_btnTextListByModel_clicked();
void on_btnTextTableByModel_clicked();
void on_btnTextTreeByModel_clicked();
void on_btnStatusVisible_clicked(); void on_btnStatusVisible_clicked();
void on_btnStatusInvisible_clicked(); void on_btnStatusInvisible_clicked();
@ -121,15 +107,8 @@ private:
QFileDialog::Options getFileDialogOptions() const; QFileDialog::Options getFileDialogOptions() const;
void onDVClicked(const QModelIndex &index);
void onDVDoubleClicked(const QModelIndex &index);
private: private:
Ui::TestForm *ui; Ui::TestForm *ui;
WingHex::ClickedCallBack _click;
WingHex::ClickedCallBack _dblclick;
}; };
#endif // TESTFORM_H #endif // TESTFORM_H

View File

@ -1050,135 +1050,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab_8">
<attribute name="title">
<string>DataVisual</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_20">
<item>
<widget class="QTextEdit" name="teDataVisual"/>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="minimumSize">
<size>
<width>0</width>
<height>150</height>
</size>
</property>
<property name="title">
<string>Type</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetMinAndMaxSize</enum>
</property>
<item row="0" column="1">
<widget class="QPushButton" name="btnTextList">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateTextList (LineByLine)</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnTextTree">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateTextTree (Json)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="btnTextTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateTextTable (Json)</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnTextListByModel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateTextListByModel</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="btnText_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateText</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="btnTextTableByModel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateTextTableByModel</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="btnTextTreeByModel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">updateTextTreeByModel</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<widget class="QLabel" name="label_13">
<property name="text">
<string notr="true">WingSummer</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_9"> <widget class="QWidget" name="tab_9">
<attribute name="title"> <attribute name="title">
<string>Others</string> <string>Others</string>
@ -1278,18 +1149,18 @@
<resources/> <resources/>
<connections> <connections>
<connection> <connection>
<sender>btnClearCtl</sender> <sender>btnClearFile</sender>
<signal>clicked()</signal> <signal>clicked()</signal>
<receiver>tbCtlLogger</receiver> <receiver>tbFileLogger</receiver>
<slot>clear()</slot> <slot>clear()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>271</x> <x>239</x>
<y>387</y> <y>388</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>318</x> <x>290</x>
<y>264</y> <y>328</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -1310,34 +1181,34 @@
</hints> </hints>
</connection> </connection>
<connection> <connection>
<sender>btnClearInput</sender> <sender>btnClearCtl</sender>
<signal>clicked()</signal> <signal>clicked()</signal>
<receiver>tbInputLogger</receiver> <receiver>tbCtlLogger</receiver>
<slot>clear()</slot> <slot>clear()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>210</x> <x>271</x>
<y>388</y> <y>387</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>236</x> <x>318</x>
<y>332</y> <y>264</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection> <connection>
<sender>btnClearFile</sender> <sender>btnClearText</sender>
<signal>clicked()</signal> <signal>clicked()</signal>
<receiver>tbFileLogger</receiver> <receiver>leToastText</receiver>
<slot>clear()</slot> <slot>clear()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>239</x> <x>569</x>
<y>388</y> <y>271</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>290</x> <x>468</x>
<y>328</y> <y>229</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>
@ -1358,18 +1229,18 @@
</hints> </hints>
</connection> </connection>
<connection> <connection>
<sender>btnClearText</sender> <sender>btnClearInput</sender>
<signal>clicked()</signal> <signal>clicked()</signal>
<receiver>leToastText</receiver> <receiver>tbInputLogger</receiver>
<slot>clear()</slot> <slot>clear()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>569</x> <x>210</x>
<y>271</y> <y>388</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>468</x> <x>236</x>
<y>229</y> <y>332</y>
</hint> </hint>
</hints> </hints>
</connection> </connection>

View File

@ -1,55 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#include "testtablemodel.h"
#include "WingPlugin/iwingpluginbase.h"
TestTableModel::TestTableModel(QObject *parent) : QAbstractTableModel(parent) {}
int TestTableModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return WingHex::SDKVERSION;
}
int TestTableModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return 5;
}
QVariant TestTableModel::data(const QModelIndex &index, int role) const {
switch (role) {
case Qt::DisplayRole:
case Qt::ToolTipRole: {
return QStringLiteral("(%1, %2)").arg(index.row()).arg(index.column());
}
case Qt::TextAlignmentRole:
return Qt::AlignCenter;
}
return QVariant();
}
QVariant TestTableModel::headerData(int section, Qt::Orientation orientation,
int role) const {
Q_UNUSED(orientation);
if (role == Qt::DisplayRole) {
return section + 1;
}
return QVariant();
}

View File

@ -1,41 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
** =============================================================================
*/
#ifndef TESTTABLEMODEL_H
#define TESTTABLEMODEL_H
#include <QAbstractTableModel>
class TestTableModel : public QAbstractTableModel {
Q_OBJECT
public:
explicit TestTableModel(QObject *parent = nullptr);
// QAbstractItemModel interface
public:
virtual int rowCount(const QModelIndex &parent) const override;
virtual int columnCount(const QModelIndex &parent) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation,
int role) const override;
};
#endif // TESTTABLEMODEL_H

@ -1 +1 @@
Subproject commit 95b3250011d0bf76ebd77f9905dc77fd04a46ce7 Subproject commit 1f53c308498e529e5cfbed16c9f7f68c77a3e8e5

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,7 @@ def run_command_interactive(command):
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
prog="mkdeb.py", description="A deb installer maker for WingHexExplorer2") prog="mkinnopak.py", description="A InnoSetup installer maker for WingHexExplorer2")
parser.add_argument( parser.add_argument(
"folder", help="A folder that has contained the binary build", type=str "folder", help="A folder that has contained the binary build", type=str
@ -275,7 +275,7 @@ Source: {#MyAppExePath}; DestDir: "{app}"; Flags: ignoreversion
iss_content += r'Root: HKCR; Subkey: "WingHexExplorer2\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},1"; Flags: noerror uninsdeletevalue; ' + '\n' iss_content += r'Root: HKCR; Subkey: "WingHexExplorer2\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},1"; Flags: noerror uninsdeletevalue; ' + '\n'
iss_content += r'Root: HKCR; Subkey: "WingHexExplorer2\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1""" ;Flags: noerror uninsdeletevalue; ' + '\n' iss_content += r'Root: HKCR; Subkey: "WingHexExplorer2\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1""" ;Flags: noerror uninsdeletevalue; ' + '\n'
iss_content += """ iss_content += r"""
[Icons] [Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -55,6 +55,7 @@
<item>typedef</item> <item>typedef</item>
<item>while</item> <item>while</item>
<item>xor</item> <item>xor</item>
<item>co_await</item>
</list> </list>
<list name="types"> <list name="types">
<item>void</item> <item>void</item>
@ -80,7 +81,7 @@
<HlCOct attribute="Octal" context="#stay"/> <HlCOct attribute="Octal" context="#stay"/>
<HlCHex attribute="Hex" context="#stay"/> <HlCHex attribute="Hex" context="#stay"/>
<Int attribute="Decimal" context="Int Suffixes"/> <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;"/> <StringDetect attribute="Text Block" context="TextBlock" String="&quot;&quot;&quot;"/>
<DetectChar attribute="String" context="String" char="&quot;"/> <DetectChar attribute="String" context="String" char="&quot;"/>
<Detect2Chars attribute="Comment" context="MatchComment" char="/" char1="/" lookAhead="true"/> <Detect2Chars attribute="Comment" context="MatchComment" char="/" char1="/" lookAhead="true"/>
@ -105,6 +106,7 @@
<context attribute="String" lineEndContext="#pop" name="String"> <context attribute="String" lineEndContext="#pop" name="String">
<DetectChar context="StringEscapedChar" char="\" lookAhead="1"/> <DetectChar context="StringEscapedChar" char="\" lookAhead="1"/>
<DetectChar attribute="String" context="#pop" char="&quot;"/> <DetectChar attribute="String" context="#pop" char="&quot;"/>
<DetectChar attribute="Char" context="#pop" char="&apos;"/>
</context> </context>
<context attribute="String" lineEndContext="#pop" name="StringEscapedChar"> <context attribute="String" lineEndContext="#pop" name="StringEscapedChar">
<HlCStringChar attribute="String Char" context="#pop"/> <HlCStringChar attribute="String Char" context="#pop"/>
@ -144,7 +146,7 @@
<itemData name="Octal" defStyleNum="dsBaseN"/> <itemData name="Octal" defStyleNum="dsBaseN"/>
<itemData name="Hex" defStyleNum="dsBaseN"/> <itemData name="Hex" defStyleNum="dsBaseN"/>
<itemData name="Float" defStyleNum="dsFloat"/> <itemData name="Float" defStyleNum="dsFloat"/>
<itemData name="Char" defStyleNum="dsChar"/> <itemData name="Char" defStyleNum="dsString"/>
<itemData name="String" defStyleNum="dsString"/> <itemData name="String" defStyleNum="dsString"/>
<itemData name="Text Block" defStyleNum="dsString"/> <itemData name="Text Block" defStyleNum="dsString"/>
<itemData name="String Char" defStyleNum="dsSpecialChar"/> <itemData name="String Char" defStyleNum="dsSpecialChar"/>

View File

@ -1,7 +1,7 @@
{ {
"Id": "WingAngelAPI", "Id": "WingAngelAPI",
"Author": "wingsummer", "Author": "wingsummer",
"Version": "2.1.0", "Version": "2.2.2",
"Vendor": "WingCloudStudio", "Vendor": "WingCloudStudio",
"License": "AGPL-3.0", "License": "AGPL-3.0",
"Url": "https://github.com/Wing-summer/WingHexExplorer2" "Url": "https://github.com/Wing-summer/WingHexExplorer2"

View File

@ -1,6 +1,6 @@
{ {
"Id" : "WingCStruct", "Id" : "WingCStruct",
"Version" : "0.0.1", "Version" : "0.0.2",
"Vendor" : "WingCloudStudio", "Vendor" : "WingCloudStudio",
"Author" : "wingsummer", "Author" : "wingsummer",
"License" : "AGPL-v3.0", "License" : "AGPL-v3.0",

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

@ -45,6 +45,8 @@ AppManager::AppManager(int &argc, char *argv[])
: QtSingleApplication(argc, argv) { : QtSingleApplication(argc, argv) {
ASSERT_SINGLETON; ASSERT_SINGLETON;
_instance = this;
LanguageManager::instance(); LanguageManager::instance();
InspectQtLogHelper::instance().init(); InspectQtLogHelper::instance().init();
CrashHandler::instance().init(); CrashHandler::instance().init();
@ -102,6 +104,8 @@ AppManager::AppManager(int &argc, char *argv[])
his.add(cmd); his.add(cmd);
} }
_timer.start();
_w = new MainWindow(splash); _w = new MainWindow(splash);
setActivationWindow(_w); setActivationWindow(_w);
@ -133,18 +137,18 @@ AppManager::AppManager(int &argc, char *argv[])
connect(_w, &MainWindow::closed, this, connect(_w, &MainWindow::closed, this,
[]() { AppManager::instance()->exit(); }); []() { AppManager::instance()->exit(); });
_instance = this;
if (splash) if (splash)
splash->close(); splash->close();
} }
AppManager::~AppManager() { AppManager::~AppManager() {
InspectQtLogHelper::instance().destory();
ClangFormatManager::instance().save(); ClangFormatManager::instance().save();
// CommandHistoryManager::save(QConsoleWidget::history().strings_); ScriptMachine::instance().deleteLater();
InspectQtLogHelper::instance().destory();
CommandHistoryManager::save(QConsoleWidget::history().strings_);
_w->deleteLater(); delete _w;
_w = nullptr; _w = nullptr;
} }
@ -152,6 +156,8 @@ AppManager *AppManager::instance() { return _instance; }
MainWindow *AppManager::mainWindow() const { return _w; } MainWindow *AppManager::mainWindow() const { return _w; }
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;
Q_ASSERT(_w); Q_ASSERT(_w);

View File

@ -21,6 +21,8 @@
#include "dialog/mainwindow.h" #include "dialog/mainwindow.h"
#include "qtsingleapplication/src/qtsingleapplication.h" #include "qtsingleapplication/src/qtsingleapplication.h"
#include <QElapsedTimer>
class AppManager : public QtSingleApplication { class AppManager : public QtSingleApplication {
Q_OBJECT Q_OBJECT
public: public:
@ -36,6 +38,8 @@ public:
QApplication::tr("WingCloudStudio"); QApplication::tr("WingCloudStudio");
} }
quint64 currentMSecsSinceEpoch();
public slots: public slots:
void openFile(const QString &file, bool autoDetect = true); void openFile(const QString &file, bool autoDetect = true);
void openRawFile(const QString &file); void openRawFile(const QString &file);
@ -43,6 +47,8 @@ public slots:
private: private:
MainWindow *_w = nullptr; MainWindow *_w = nullptr;
QElapsedTimer _timer;
static AppManager *_instance; static AppManager *_instance;
}; };

View File

@ -24,36 +24,17 @@
asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {} asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {}
asBuilder::~asBuilder() { int asBuilder::build(asIScriptModule *module) {
if (module) {
module->Discard();
}
}
int asBuilder::StartNewModule(const char *moduleName) {
if (module) {
module->Discard();
}
module = engine->GetModule(moduleName, asGM_ALWAYS_CREATE);
if (module == nullptr)
return -1;
ClearAll();
return 0;
}
asIScriptModule *asBuilder::GetModule() { return module; }
int asBuilder::Build() {
Q_ASSERT(module); Q_ASSERT(module);
if (module == nullptr) { if (module == nullptr) {
return -1; return -1;
} }
module->ResetGlobalVars();
for (auto &mod : modifiedScripts) { for (auto &mod : modifiedScripts) {
module->AddScriptSection(mod.section.toUtf8(), mod.script.data(), module->AddScriptSection(mod.section.toUtf8(), mod.script.data(),
mod.script.size(), mod.lineOffset); mod.script.size());
} }
int r = module->Build(); int r = module->Build();

View File

@ -27,19 +27,10 @@
class asBuilder : public AsPreprocesser { class asBuilder : public AsPreprocesser {
public: public:
explicit asBuilder(asIScriptEngine *engine); explicit asBuilder(asIScriptEngine *engine);
virtual ~asBuilder();
// Start a new module public:
virtual int StartNewModule(const char *moduleName); // build the added script sections
int build(asIScriptModule *module);
// Build the added script sections
virtual int Build();
// Returns the current module
asIScriptModule *GetModule();
protected:
asIScriptModule *module = nullptr;
}; };
#endif // ASBUILDER_H #endif // ASBUILDER_H

View File

@ -18,10 +18,16 @@
#include "ascompletion.h" #include "ascompletion.h"
#include "asdatabase.h" #include "asdatabase.h"
#include "class/aspreprocesser.h"
#include "class/qascodeparser.h"
#include "class/scriptmachine.h"
#include "control/scripteditor.h"
#include "model/codecompletionmodel.h" #include "model/codecompletionmodel.h"
#include "utilities.h"
#include "wingcodeedit.h" #include "wingcodeedit.h"
#include <QAbstractItemView> #include <QAbstractItemView>
#include <QApplication>
#include <QByteArray> #include <QByteArray>
#include <QDir> #include <QDir>
#include <QEvent> #include <QEvent>
@ -36,17 +42,17 @@ Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DOT_TRIGGER, ("."))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DBL_COLON_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, LEFT_PARE_TRIGGER, ("("))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";"))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SHARP_TRIGGER, ("#"))
AsCompletion::AsCompletion(asIScriptEngine *engine, WingCodeEdit *p) AsCompletion::AsCompletion(WingCodeEdit *p)
: WingCompleter(p), parser(engine), _engine(engine), : WingCompleter(p), parser(ScriptMachine::instance().engine()) {
m_parseDocument(false) {
Q_ASSERT(engine);
setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER, setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER,
// unleash the power of call tips // unleash the power of call tips
*LEFT_PARE_TRIGGER, *LEFT_PARE_TRIGGER,
// clear the tips // clear the tips
*SEMI_COLON_TRIGGER}); *SEMI_COLON_TRIGGER,
// for marcos
*SHARP_TRIGGER});
setTriggerAmount(3); setTriggerAmount(3);
connect(this, QOverload<const QModelIndex &>::of(&AsCompletion::activated), connect(this, QOverload<const QModelIndex &>::of(&AsCompletion::activated),
@ -63,8 +69,10 @@ AsCompletion::AsCompletion(asIScriptEngine *engine, WingCodeEdit *p)
AsCompletion::~AsCompletion() {} AsCompletion::~AsCompletion() {}
void AsCompletion::applyEmptyNsNode(QList<CodeInfoTip> &nodes) { void AsCompletion::applyEmptyNsNode(QList<CodeInfoTip> &nodes,
const QList<CodeInfoTip> &docNodes) {
static QList<CodeInfoTip> emptyNsNodes; static QList<CodeInfoTip> emptyNsNodes;
if (emptyNsNodes.isEmpty()) { if (emptyNsNodes.isEmpty()) {
auto &hn = parser.headerNodes(); auto &hn = parser.headerNodes();
for (auto p = hn.constKeyValueBegin(); p != hn.constKeyValueEnd(); for (auto p = hn.constKeyValueBegin(); p != hn.constKeyValueEnd();
@ -80,7 +88,34 @@ void AsCompletion::applyEmptyNsNode(QList<CodeInfoTip> &nodes) {
} }
emptyNsNodes.append(parser.keywordNodes()); emptyNsNodes.append(parser.keywordNodes());
} }
nodes = emptyNsNodes;
nodes.clear();
for (auto &p : docNodes) {
if (p.nameSpace.isEmpty()) {
nodes.append(p);
} else {
if (p.dontAddGlobal) {
continue;
}
CodeInfoTip tip;
tip.type = CodeInfoTip::Type::Group;
tip.name = p.nameSpace;
nodes.append(tip);
}
if (p.type == CodeInfoTip::Type::Class) {
for (auto &c : p.children) {
if (c.type == CodeInfoTip::Type::ClsFunction ||
c.type == CodeInfoTip::Type::Property) {
nodes.append(c);
}
}
}
}
nodes.append(emptyNsNodes);
} }
void AsCompletion::applyClassNodes(QList<CodeInfoTip> &nodes) { void AsCompletion::applyClassNodes(QList<CodeInfoTip> &nodes) {
@ -91,7 +126,7 @@ void AsCompletion::applyClassNodes(QList<CodeInfoTip> &nodes) {
for (auto &item : n) { for (auto &item : n) {
if (item.type == CodeInfoTip::Type::Class) { if (item.type == CodeInfoTip::Type::Class) {
for (auto &c : item.children) { for (auto &c : item.children) {
if (c.type == CodeInfoTip::Type::Function) { if (c.type == CodeInfoTip::Type::ClsFunction) {
if (!c.addinfo.contains(CodeInfoTip::RetType)) { if (!c.addinfo.contains(CodeInfoTip::RetType)) {
continue; continue;
} }
@ -105,43 +140,112 @@ void AsCompletion::applyClassNodes(QList<CodeInfoTip> &nodes) {
nodes = clsNodes; nodes = clsNodes;
} }
bool AsCompletion::parseDocument() const { return m_parseDocument; } int AsCompletion::includeCallBack(const QString &include, bool quotedInclude,
const QString &from, AsPreprocesser *builder,
void *userParam) {
auto p = reinterpret_cast<AsCompletion *>(userParam);
void AsCompletion::setParseDocument(bool newParseDocument) { QFileInfo info(include);
m_parseDocument = newParseDocument; bool isAbsolute = info.isAbsolute();
bool hasNoExt = info.suffix().isEmpty();
QString inc;
if (quotedInclude) {
if (isAbsolute) {
inc = include;
} else {
auto editor = qobject_cast<ScriptEditor *>(p->widget()->parent());
Q_ASSERT(editor);
auto pwd = QFileInfo(editor->fileName()).absoluteDir();
inc = pwd.absoluteFilePath(include);
}
} else {
// absolute include is not allowed in #include<>
if (isAbsolute) {
// ignored in code completion
return asSUCCESS;
}
QDir dir(qApp->applicationDirPath());
if (!dir.cd(QStringLiteral("aslib"))) {
// someone crash the software, ignored
return asSUCCESS;
}
inc = dir.absoluteFilePath(include);
}
if (hasNoExt) {
inc += QStringLiteral(".as");
}
builder->loadSectionFromFile(inc);
return asSUCCESS;
}
void AsCompletion::pushCompleteDBData(const QString &fileName,
const QList<CodeInfoTip> &data) {
if (!QFile::exists(fileName)) {
return;
}
CompleteDB c;
c.data = data;
c.md5 = Utilities::getMd5(fileName);
c.time = 3;
comdb.insert(fileName, c);
}
void AsCompletion::remoteCompleteDBData(const QString &fileName) {
comdb.remove(fileName);
}
std::optional<AsCompletion::CompleteDB>
AsCompletion::getCompleteDBData(const QString &fileName) {
if (comdb.contains(fileName)) {
auto ret = comdb[fileName];
ret.time++;
return ret;
}
return std::nullopt;
}
void AsCompletion::clearCompleteDBUnused() {
for (auto &c : comdb) {
c.time--;
}
comdb.removeIf(
[](const QPair<QString, CompleteDB> &c) { return c.second.time == 0; });
} }
void AsCompletion::clearFunctionTip() { emit onFunctionTip({}); } void AsCompletion::clearFunctionTip() { emit onFunctionTip({}); }
QString AsCompletion::wordSeperators() const { QString AsCompletion::wordSeperators() const {
static QString eow(QStringLiteral("~!@#$%^&*()_+{}|\"<>?,/;'[]\\-=")); static QString eow(QStringLiteral("~!@$%^&*()_+{}|\"<>?,/;'[]\\-="));
return eow; return eow;
} }
void AsCompletion::processTrigger(const QString &trigger, bool AsCompletion::processTrigger(const QString &trigger,
const QString &content) { const QString &content) {
QList<CodeInfoTip> nodes;
if (trigger == *SHARP_TRIGGER) {
setModel(new CodeCompletionModel(parseMarcos(), this));
setCompletionPrefix({});
return true;
}
if (content.isEmpty()) { if (content.isEmpty()) {
return; return false;
} }
if (trigger == *SEMI_COLON_TRIGGER) { if (trigger == *SEMI_COLON_TRIGGER) {
clearFunctionTip(); clearFunctionTip();
return; return false;
} }
auto len = content.length(); auto len = content.length();
auto code = content.toUtf8(); auto code = content.toUtf8();
QList<CodeInfoTip> nodes;
// TODO: PRs are welcomed !!!
// If this software is well-known or brings me lots of
// financial support, I will implement it myself.
// PARSING THE DOCUMENT
if (m_parseDocument) {
nodes.append(parseDocument());
}
if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) { if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) {
clearFunctionTip(); clearFunctionTip();
} }
@ -155,12 +259,14 @@ void AsCompletion::processTrigger(const QString &trigger,
QByteArray content; QByteArray content;
}; };
auto engine = ScriptMachine::instance().engine();
// parse the tokens // parse the tokens
QVector<Token> tokens; QVector<Token> tokens;
qsizetype pos = 0; qsizetype pos = 0;
for (; p < end;) { for (; p < end;) {
asUINT tokenLen = 0; asUINT tokenLen = 0;
auto tt = _engine->ParseToken(p, len, &tokenLen); auto tt = engine->ParseToken(p, len, &tokenLen);
if (tt == asTC_WHITESPACE) { if (tt == asTC_WHITESPACE) {
p += tokenLen; p += tokenLen;
pos += tokenLen; pos += tokenLen;
@ -203,22 +309,45 @@ void AsCompletion::processTrigger(const QString &trigger,
QByteArray fn; QByteArray fn;
if (tokens.isEmpty()) { if (tokens.isEmpty()) {
popup()->hide(); popup()->hide();
return; return false;
} }
QString prefix;
auto etoken = tokens.back(); 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();
return false;
}
if (trigger.isEmpty() && popup()->isVisible()) {
setCompletionPrefix(prefix);
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 // if trigger is empty, it's making editing
if (trigger.isEmpty()) { if (trigger.isEmpty()) {
// it can not be any trigger, so take the last as prefix
prefix = etoken.content;
tokens.removeLast(); tokens.removeLast();
if (tokens.isEmpty()) { if (tokens.isEmpty()) {
applyEmptyNsNode(nodes); applyEmptyNsNode(nodes, docNodes);
} else { } else {
etoken = tokens.back(); // checking later etoken = tokens.back(); // checking later
} }
} else {
prefix.clear();
} }
if (nodes.isEmpty()) { if (nodes.isEmpty()) {
@ -227,21 +356,82 @@ void AsCompletion::processTrigger(const QString &trigger,
if (etoken.content == *DBL_COLON_TRIGGER) { if (etoken.content == *DBL_COLON_TRIGGER) {
processTrigger(*DBL_COLON_TRIGGER, content.left(etoken.pos)); processTrigger(*DBL_COLON_TRIGGER, content.left(etoken.pos));
setCompletionPrefix(prefix); setCompletionPrefix(prefix);
return; return true;
} else if (etoken.content == *DOT_TRIGGER) { } else if (etoken.content == *DOT_TRIGGER) {
processTrigger(*DOT_TRIGGER, content.left(etoken.pos)); processTrigger(*DOT_TRIGGER, content.left(etoken.pos));
setCompletionPrefix(prefix); setCompletionPrefix(prefix);
return; return true;
} else if (etoken.content == QByteArrayLiteral(")")) {
// ignore
} else { } else {
applyEmptyNsNode(nodes); applyEmptyNsNode(nodes, docNodes);
} }
} else if (etoken.type != asTC_IDENTIFIER) { } else if (etoken.type != asTC_IDENTIFIER) {
popup()->hide(); popup()->hide();
return; return false;
} }
if (trigger == *DOT_TRIGGER) { if (trigger == *DOT_TRIGGER) {
applyClassNodes(nodes); if (etoken.type == asTC_IDENTIFIER) {
// member type guessing ? basic match is enough. (>n<)
auto isBasicType = [](const QByteArray &type) {
static QByteArrayList basicType{
"int", "int8", "int16", "int32", "int64",
"uint", "uint8", "uint16", "uint32", "uint64",
"float", "double", "byte"};
return basicType.contains(type);
};
auto clsNodes = parser.classNodes();
// filter the type we can use to auto-complete in docNodes
for (auto &item : docNodes) {
if (item.type == CodeInfoTip::Type::Class) {
auto name = item.nameSpace;
if (name.isEmpty()) {
name = item.name;
} else {
name += QStringLiteral("::") + item.name;
}
clsNodes.insert(name, item.children);
}
// a typedef can only be used to define an alias
// for primitive types, so NO NEED for auto-completing
}
tokens.removeLast();
auto ns = getNamespace(tokens);
for (auto &item : docNodes) {
if (etoken.content == item.name && ns == item.nameSpace) {
auto retType = item.addinfo.value(CodeInfoTip::RetType);
auto decl = engine->GetTypeInfoByDecl(retType.toUtf8());
if (decl) {
QByteArray type = decl->GetNamespace();
if (type.isEmpty()) {
type = decl->GetName();
} else {
type +=
(QByteArrayLiteral("::") + decl->GetName());
}
// auto type inference is not supported.
// PRs will be welcomed !!!
if (isBasicType(type)) {
popup()->hide();
return false;
}
nodes.append(clsNodes.value(type));
break;
}
}
}
}
if (nodes.isEmpty()) {
applyClassNodes(nodes);
}
} else if (etoken.content.length() >= triggerAmount()) { } else if (etoken.content.length() >= triggerAmount()) {
// completion for a.b.c or a::b.c or a::b::c.d or ::a::b.c // completion for a.b.c or a::b.c or a::b::c.d or ::a::b.c
if (trigger == *DBL_COLON_TRIGGER) { if (trigger == *DBL_COLON_TRIGGER) {
@ -250,12 +440,19 @@ void AsCompletion::processTrigger(const QString &trigger,
if (idx >= 0) { if (idx >= 0) {
if (tokens.at(idx).content == *DOT_TRIGGER) { if (tokens.at(idx).content == *DOT_TRIGGER) {
popup()->hide(); popup()->hide();
return; return false;
} }
} }
nodes = parser.headerNodes().value(ns); nodes = parser.headerNodes().value(ns) +
parser.enumsNodes().value(ns);
for (auto &n : docNodes) {
if (n.nameSpace == ns) {
nodes.append(n);
}
}
if (nodes.isEmpty()) { if (nodes.isEmpty()) {
return; return true;
} }
} else if (trigger == *LEFT_PARE_TRIGGER) { } else if (trigger == *LEFT_PARE_TRIGGER) {
// the first is function name, an identifier // the first is function name, an identifier
@ -271,12 +468,14 @@ void AsCompletion::processTrigger(const QString &trigger,
if (idx >= 0 && idx < tokens.length()) { if (idx >= 0 && idx < tokens.length()) {
if (tokens.at(idx).content == *DOT_TRIGGER) { if (tokens.at(idx).content == *DOT_TRIGGER) {
popup()->hide(); popup()->hide();
return; return false;
} }
} }
nodes = parser.headerNodes().value(ns); nodes = parser.headerNodes().value(ns);
if (nodes.isEmpty()) { if (nodes.isEmpty()) {
applyEmptyNsNode(nodes); applyEmptyNsNode(nodes, docNodes);
} }
} }
} }
@ -284,9 +483,184 @@ void AsCompletion::processTrigger(const QString &trigger,
setModel(new CodeCompletionModel(nodes, this)); setModel(new CodeCompletionModel(nodes, this));
setCompletionPrefix(prefix); setCompletionPrefix(prefix);
return true;
} }
QList<CodeInfoTip> AsCompletion::parseDocument() { return {}; } QList<CodeInfoTip> AsCompletion::parseDocument() {
auto editor = qobject_cast<WingCodeEdit *>(widget());
if (editor == nullptr) {
return {};
}
auto code = editor->toPlainText();
auto engine = ScriptMachine::instance().engine();
// first preprocess the code
AsPreprocesser prepc(engine);
prepc.setIsCodeCompleteMode(true);
prepc.setIncludeCallback(&AsCompletion::includeCallBack, this);
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"),
code.toUtf8());
if (r <= 0) {
return {};
}
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;
QList<CodeInfoTip> dd;
if (d.section == QStringLiteral("ASCOMPLETION")) {
offset = editor->textCursor().position();
} else {
auto r = getCompleteDBData(d.section);
if (r) {
auto md5 = r->md5;
if (Utilities::getMd5(d.section) == md5) {
dd = r->data;
} else {
remoteCompleteDBData(d.section);
}
}
}
if (dd.isEmpty()) {
dd = parseScriptData(offset, d.script);
if (offset < 0) {
pushCompleteDBData(d.section, dd);
}
}
ret.append(dd);
}
return ret;
}
QList<CodeInfoTip> AsCompletion::parseMarcos() {
static QList<CodeInfoTip> marcos;
if (marcos.isEmpty()) {
QStringList m{"define", "undef", "if", "else", "endif",
"ifdef", "ifndef", "include", "pragma"};
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;
auto engine = ScriptMachine::instance().engine();
QAsCodeParser parser(engine);
auto syms = parser.parseAndIntell(offset, code);
for (auto &sym : syms) {
CodeInfoTip tip;
tip.name = sym.name;
tip.nameSpace = QString::fromUtf8(sym.scope.join("::"));
switch (sym.symtype) {
case QAsCodeParser::SymbolType::Function:
case QAsCodeParser::SymbolType::FnDef:
tip.type = CodeInfoTip::Type::Function;
tip.addinfo.insert(CodeInfoTip::RetType,
QString::fromUtf8(sym.type));
tip.addinfo.insert(CodeInfoTip::Args,
QString::fromUtf8(sym.additonalInfo));
for (auto &var : sym.children) {
CodeInfoTip va;
va.dontAddGlobal = true;
va.name = var.name;
va.nameSpace = QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable;
ret.append(va);
}
break;
case QAsCodeParser::SymbolType::Enum:
tip.type = CodeInfoTip::Type::Enum;
for (auto &e : sym.children) {
CodeInfoTip en;
en.dontAddGlobal = true;
en.name = e.name;
en.nameSpace = QString::fromUtf8(e.scope.join("::"));
en.type = CodeInfoTip::Type::Enumerater;
if (!e.additonalInfo.isEmpty()) {
en.addinfo.insert(CodeInfoTip::Comment,
en.name + QStringLiteral(" = ") +
e.additonalInfo);
}
ret.append(en);
}
break;
case QAsCodeParser::SymbolType::TypeDef:
tip.type = CodeInfoTip::Type::TypeDef;
break;
case QAsCodeParser::SymbolType::Variable:
tip.addinfo.insert(CodeInfoTip::RetType, sym.type);
tip.type = CodeInfoTip::Type::Variable;
break;
case QAsCodeParser::SymbolType::Class:
case QAsCodeParser::SymbolType::Interface:
for (auto &mem : sym.children) {
if (mem.vis != QAsCodeParser::Visiblity::Public) {
continue;
}
CodeInfoTip ctip;
ctip.name = mem.name;
ctip.nameSpace = QString::fromUtf8(mem.scope.join("::"));
if (mem.symtype == QAsCodeParser::SymbolType::Function) {
ctip.type = CodeInfoTip::Type::Function;
ctip.addinfo.insert(CodeInfoTip::RetType,
QString::fromUtf8(mem.type));
ctip.addinfo.insert(CodeInfoTip::Args,
QString::fromUtf8(mem.additonalInfo));
for (auto &var : mem.children) {
CodeInfoTip va;
va.dontAddGlobal = true;
va.name = var.name;
va.nameSpace = QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable;
tip.children.append(va);
}
tip.children.append(ctip);
} else if (mem.symtype == QAsCodeParser::SymbolType::Variable) {
ctip.addinfo.insert(CodeInfoTip::RetType, mem.type);
ctip.type = CodeInfoTip::Type::Variable;
tip.children.append(ctip);
}
}
tip.type = CodeInfoTip::Type::Class;
break;
case QAsCodeParser::SymbolType::Invalid:
case QAsCodeParser::SymbolType::Import:
continue;
}
ret.append(tip);
}
return ret;
}
bool AsCompletion::eventFilter(QObject *watched, QEvent *event) { bool AsCompletion::eventFilter(QObject *watched, QEvent *event) {
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {

View File

@ -21,10 +21,12 @@
#include "WingCodeEdit/wingcompleter.h" #include "WingCodeEdit/wingcompleter.h"
#include "class/asdatabase.h" #include "class/asdatabase.h"
class AsPreprocesser;
class AsCompletion : public WingCompleter { class AsCompletion : public WingCompleter {
Q_OBJECT Q_OBJECT
public: public:
explicit AsCompletion(asIScriptEngine *engine, WingCodeEdit *p); explicit AsCompletion(WingCodeEdit *p);
virtual ~AsCompletion(); virtual ~AsCompletion();
@ -32,17 +34,19 @@ public:
public: public:
virtual QString wordSeperators() const override; virtual QString wordSeperators() const override;
bool parseDocument() const;
void setParseDocument(bool newParseDocument);
void clearFunctionTip(); void clearFunctionTip();
protected: protected:
virtual void processTrigger(const QString &trigger, virtual bool processTrigger(const QString &trigger,
const QString &content) override; const QString &content) override;
virtual QList<CodeInfoTip> parseDocument(); virtual QList<CodeInfoTip> parseDocument();
virtual QList<CodeInfoTip> parseMarcos();
QList<CodeInfoTip> parseScriptData(qsizetype offset,
const QByteArray &code);
signals: signals:
void onFunctionTip(const QString &content); void onFunctionTip(const QString &content);
@ -51,13 +55,32 @@ public:
virtual bool eventFilter(QObject *watched, QEvent *event) override; virtual bool eventFilter(QObject *watched, QEvent *event) override;
private: private:
void applyEmptyNsNode(QList<CodeInfoTip> &nodes); void applyEmptyNsNode(QList<CodeInfoTip> &nodes,
const QList<CodeInfoTip> &docNodes);
void applyClassNodes(QList<CodeInfoTip> &nodes); void applyClassNodes(QList<CodeInfoTip> &nodes);
private:
static int includeCallBack(const QString &include, bool quotedInclude,
const QString &from, AsPreprocesser *builder,
void *userParam);
private:
struct CompleteDB {
QList<CodeInfoTip> data;
QByteArray md5;
uint time = 0;
};
QHash<QString, CompleteDB> comdb;
void pushCompleteDBData(const QString &fileName,
const QList<CodeInfoTip> &data);
std::optional<CompleteDB> getCompleteDBData(const QString &fileName);
void remoteCompleteDBData(const QString &fileName);
void clearCompleteDBUnused();
private: private:
ASDataBase parser; ASDataBase parser;
asIScriptEngine *_engine;
bool m_parseDocument;
}; };
#endif // _CPP_COMPLETION_H_ #endif // _CPP_COMPLETION_H_

View File

@ -1,12 +1,108 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "asconsolecompletion.h" #include "asconsolecompletion.h"
#include "AngelScript/sdk/angelscript/source/as_module.h"
#include "class/qascodeparser.h"
#include "control/scriptingconsole.h" #include "control/scriptingconsole.h"
AsConsoleCompletion::AsConsoleCompletion(asIScriptEngine *engine, AsConsoleCompletion::AsConsoleCompletion(ScriptingConsole *p)
ScriptingConsole *p) : AsCompletion(p), _console(p) {}
: AsCompletion(engine, p), _console(p) {}
QList<CodeInfoTip> AsConsoleCompletion::parseDocument() { QList<CodeInfoTip> AsConsoleCompletion::parseDocument() {
// TODO auto editor = _console;
return {}; if (editor == nullptr) {
return {};
}
auto code = editor->currentCodes();
auto engine = ScriptMachine::instance().engine();
QAsCodeParser parser(engine);
auto seg = parser.parse(code.toUtf8());
if (std::find_if(seg.begin(), seg.end(),
[](const QAsCodeParser::CodeSegment &seg) {
return seg.isValid();
}) == seg.end()) {
// wrap it to let code-completion work
code.prepend("void f(){").append('}');
}
// first preprocess the code
AsPreprocesser prepc(engine);
// including is not supported in console
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASConCOMPLETION"),
code.toUtf8());
if (r <= 0) {
return {};
}
QList<CodeInfoTip> citips;
// first, global variables should be added into
auto rmod = ScriptMachine::instance().module(ScriptMachine::Interactive);
// I think hijack the internal will do the better
auto mod = dynamic_cast<asCModule *>(rmod);
if (mod) {
auto it = mod->m_scriptGlobals.List();
while (it) {
// lamda expression is great!
auto CString2ByteArray = [](const asCString &str) -> QByteArray {
return QByteArray(str.AddressOf(), str.GetLength());
};
CodeInfoTip tip;
tip.type = CodeInfoTip::Type::Variable;
tip.addinfo.insert(
CodeInfoTip::RetType,
CString2ByteArray(it->type.Format(mod->m_defaultNamespace)));
tip.nameSpace = CString2ByteArray(it->nameSpace->name);
tip.name = CString2ByteArray(it->name);
citips.append(tip);
it++;
}
}
auto data = prepc.scriptData();
if (data.size() == 1) {
auto d = data[0];
return citips + parseScriptData(d.script.length() - 1, d.script);
} else {
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

@ -1,3 +1,20 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef ASCONSOLECOMPLETION_H #ifndef ASCONSOLECOMPLETION_H
#define ASCONSOLECOMPLETION_H #define ASCONSOLECOMPLETION_H
@ -8,12 +25,12 @@ class ScriptingConsole;
class AsConsoleCompletion : public AsCompletion { class AsConsoleCompletion : public AsCompletion {
Q_OBJECT Q_OBJECT
public: public:
explicit AsConsoleCompletion(asIScriptEngine *engine, ScriptingConsole *p); explicit AsConsoleCompletion(ScriptingConsole *p);
virtual ~AsConsoleCompletion() = default; virtual ~AsConsoleCompletion() = default;
// AsCompletion interface
protected: protected:
virtual QList<CodeInfoTip> parseDocument() override; virtual QList<CodeInfoTip> parseDocument() override;
virtual QList<CodeInfoTip> parseMarcos() override;
private: private:
ScriptingConsole *_console; ScriptingConsole *_console;

View File

@ -1,22 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "ascontextmgr.h"
asContextMgr::asContextMgr() : CContextMgr() {}
bool asContextMgr::isRunning() const { return !m_threads.empty(); }

View File

@ -40,7 +40,8 @@ ASDataBase::ASDataBase(asIScriptEngine *engine) {
"function", "interface", "shared", "this", "explicit", "override", "function", "interface", "shared", "this", "explicit", "override",
"namespace", "get", "set", "super", "mixin", "false", "namespace", "get", "set", "super", "mixin", "false",
"true", "null", "typename", "return", "typedef", "funcdef", "true", "null", "typename", "return", "typedef", "funcdef",
"from", "import", "not", "xor", "or", "is"}; "from", "import", "not", "xor", "or", "is",
"co_await"};
for (auto &k : kws) { for (auto &k : kws) {
CodeInfoTip t; CodeInfoTip t;
t.type = CodeInfoTip::Type::KeyWord; t.type = CodeInfoTip::Type::KeyWord;
@ -177,6 +178,10 @@ const QHash<QString, QList<CodeInfoTip>> &ASDataBase::headerNodes() const {
return _headerNodes; return _headerNodes;
} }
const QHash<QString, QList<CodeInfoTip>> &ASDataBase::enumsNodes() const {
return _enumsNodes;
}
void ASDataBase::addGlobalFunctionCompletion(asIScriptEngine *engine) { void ASDataBase::addGlobalFunctionCompletion(asIScriptEngine *engine) {
Q_ASSERT(engine); Q_ASSERT(engine);
@ -210,6 +215,13 @@ void ASDataBase::addEnumCompletion(asIScriptEngine *engine) {
einfo.name = etype->GetName(); einfo.name = etype->GetName();
einfo.type = CodeInfoTip::Type::Enum; einfo.type = CodeInfoTip::Type::Enum;
auto ens = einfo.nameSpace;
if (ens.isEmpty()) {
ens = einfo.name;
} else {
ens += QStringLiteral("::") + einfo.name;
}
for (asUINT i = 0; i < etype->GetEnumValueCount(); ++i) { for (asUINT i = 0; i < etype->GetEnumValueCount(); ++i) {
int v; int v;
auto e = etype->GetEnumValueByIndex(i, &v); auto e = etype->GetEnumValueByIndex(i, &v);
@ -221,6 +233,7 @@ void ASDataBase::addEnumCompletion(asIScriptEngine *engine) {
QStringLiteral(" = ") + QStringLiteral(" = ") +
QString::number(v)); QString::number(v));
einfo.children.append(en); einfo.children.append(en);
_enumsNodes[ens].append(en);
} }
etype->Release(); etype->Release();
@ -313,6 +326,42 @@ void ASDataBase::addClassCompletion(asIScriptEngine *engine) {
obj->Release(); obj->Release();
_headerNodes[ns].append(cls); _headerNodes[ns].append(cls);
auto cat = cls.nameSpace;
if (cat.isEmpty()) {
cat = cls.name;
} else {
cat += QStringLiteral("::") + cls.name;
}
auto data = cls.children;
data.removeIf([](const CodeInfoTip &tip) {
static QStringList opList{
"opNeg", "opCom", "opPreInc", "opPreDec",
"opPostInc", "opPostDec", "opEquals", "opCmp",
"opEquals", "opAssign", "opAddAssign", "opSubAssign",
"opMulAssign", "opDivAssign", "opModAssign", "opPowAssign",
"opAndAssign", "opOrAssign", "opXorAssign", "opShlAssign",
"opShrAssign", "opUShrAssign", "opAdd", "opAdd_r",
"opSub", "opSub_r", "opMul", "opMul_r",
"opDiv", "opDiv_r", "opMod", "opMod_r",
"opPow", "opPow_r", "opAnd", "opAnd_r",
"opOr", "opOr_r", "opXor", "opXor_r",
"opShl", "opShl_r", "opShr", "opShr_r",
"opUShr", "opUShr_r", "opIndex", "opCall",
"opConv", "opImplConv", "opCast", "opImplCast"};
return tip.addinfo.value(CodeInfoTip::RetType).isEmpty() ||
opList.contains(tip.name);
});
for (auto &d : data) {
d.addinfo.insert(
CodeInfoTip::Comment,
d.addinfo.value(CodeInfoTip::RetType) + QStringLiteral(" ") +
d.name + QStringLiteral("(") +
d.addinfo.value(CodeInfoTip::Args) + QStringLiteral(") ") +
d.addinfo.value(CodeInfoTip::SuffixQualifier));
}
_classNodes[cat].append(data);
} }
} }
@ -323,6 +372,10 @@ QString ASDataBase::getSuffixQualifier(asIScriptFunction *fn) {
return {}; return {};
} }
const QHash<QString, QList<CodeInfoTip>> &ASDataBase::classNodes() const {
return _classNodes;
}
const QList<CodeInfoTip> &ASDataBase::keywordNodes() const { const QList<CodeInfoTip> &ASDataBase::keywordNodes() const {
return _keywordNode; return _keywordNode;
} }

View File

@ -42,6 +42,8 @@ private:
public: public:
const QHash<QString, QList<CodeInfoTip>> &headerNodes() const; const QHash<QString, QList<CodeInfoTip>> &headerNodes() const;
const QHash<QString, QList<CodeInfoTip>> &enumsNodes() const;
const QHash<QString, QList<CodeInfoTip>> &classNodes() const;
const QList<CodeInfoTip> &keywordNodes() const; const QList<CodeInfoTip> &keywordNodes() const;
@ -55,6 +57,8 @@ private:
private: private:
// <namespace, content> // <namespace, content>
QHash<QString, QList<CodeInfoTip>> _headerNodes; QHash<QString, QList<CodeInfoTip>> _headerNodes;
QHash<QString, QList<CodeInfoTip>> _enumsNodes;
QHash<QString, QList<CodeInfoTip>> _classNodes;
QList<CodeInfoTip> _keywordNode; QList<CodeInfoTip> _keywordNode;
}; };

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>
@ -71,10 +72,57 @@ void asDebugger::takeCommands(asIScriptContext *ctx) {
void asDebugger::lineCallback(asIScriptContext *ctx) { void asDebugger::lineCallback(asIScriptContext *ctx) {
Q_ASSERT(ctx); Q_ASSERT(ctx);
// prevent UI freezing
qApp->processEvents();
// This should never happen, but it doesn't hurt to validate it // This should never happen, but it doesn't hurt to validate it
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 timeOutTime = reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_TimeOut));
auto mode = reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_ContextMode));
bool timeOut = false;
if (timer < 0) {
timeOut = true;
} else {
if (mode == 0) {
timeOut = (now - timer) > 3000; // 3 s
} else {
if (timeOutTime) {
timeOut = (now - timer) > timeOutTime; // 10 min
}
}
}
if (timeOut && mode) {
auto timeOut = tr("ScriptTimedOut");
ScriptMachine::MessageInfo info;
info.message = timeOut;
info.mode = ScriptMachine::ConsoleMode(mode);
info.type = ScriptMachine::MessageType::Error;
ScriptMachine::instance().outputMessage(info);
ctx->Abort();
return;
}
auto isDbg = reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_isDbg));
if (!isDbg) {
return;
}
const char *file = 0; const char *file = 0;
int col = 0; int col = 0;
int lineNbr = ctx->GetLineNumber(0, &col, &file); int lineNbr = ctx->GetLineNumber(0, &col, &file);
@ -98,12 +146,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);
@ -359,7 +401,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>");
@ -436,7 +478,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);
} }
} }
} }
@ -473,7 +516,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 << ')';
@ -500,6 +543,8 @@ asDebugger::GCStatistic asDebugger::gcStatistics() {
void asDebugger::runDebugAction(DebugAction action) { m_action = action; } void asDebugger::runDebugAction(DebugAction action) { m_action = action; }
void asDebugger::resetState() { m_action = CONTINUE; }
void asDebugger::deleteDbgContextInfo(void *info) { void asDebugger::deleteDbgContextInfo(void *info) {
if (info) { if (info) {
delete reinterpret_cast<ContextDbgInfo *>(info); delete reinterpret_cast<ContextDbgInfo *>(info);

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,14 +108,16 @@ 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();
void runDebugAction(DebugAction action); void runDebugAction(DebugAction action);
DebugAction currentState() const; DebugAction currentState() const;
void resetState();
static void deleteDbgContextInfo(void *info); static void deleteDbgContextInfo(void *info);

File diff suppressed because it is too large Load Diff

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>
* * #ifndef <word>
*/
class AsPreprocesser { class AsPreprocesser {
public: public:
explicit AsPreprocesser(asIScriptEngine *engine); explicit AsPreprocesser(asIScriptEngine *engine);
@ -70,7 +81,6 @@ public:
public: public:
struct ScriptData { struct ScriptData {
QString section; QString section;
int lineOffset = -1;
QByteArray script; QByteArray script;
}; };
@ -79,41 +89,59 @@ public:
// Returns 1 if the file was included // Returns 1 if the file was included
// 0 if the file had already been included before // 0 if the file had already been included before
// <0 on error // <0 on error
int AddSectionFromFile(const QString &filename); int loadSectionFromFile(const QString &filename);
int loadSectionFromMemory(const QString &section, const QByteArray &code);
QList<ScriptData> GetScriptData() const; void addScriptSection(const QString &section, const QByteArray &code);
QList<ScriptData> scriptData() const;
// Returns the engine // Returns the engine
asIScriptEngine *GetEngine(); asIScriptEngine *getEngine();
// Register the callback for resolving include directive // Register the callback for resolving include directive
void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); void setIncludeCallback(INCLUDECALLBACK_t callback, void *userParam);
// Register the callback for resolving pragma directive // Register the callback for resolving pragma directive
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); bool defineWord(const QString &word, const QByteArray &value = {});
// Enumerate included script sections // Enumerate included script sections
unsigned int GetSectionCount() const; unsigned int sectionCount() const;
QString GetSectionName(unsigned int idx) const; QString sectionName(unsigned int idx) const;
bool isCodeCompleteMode() const;
void setIsCodeCompleteMode(bool newIsCodeCompleteMode);
QHash<QString, QByteArray> definedMacros() const;
protected: protected:
void ClearAll(); QString translate(const char *str);
int ProcessScriptSection(const QByteArray &script, int length,
const QString &sectionname, int lineOffset);
int LoadScriptSection(const QString &filename);
bool IncludeIfNotAlreadyIncluded(const QString &filename);
int SkipStatement(const QByteArray &modifiedScript, int pos); protected:
void clearAll();
int ExcludeCode(QByteArray &modifiedScript, int pos); int processScriptSection(const QByteArray &script,
void OverwriteCode(QByteArray &modifiedScript, int start, int len); const QString &sectionname);
int loadScriptSection(const QString &filename);
bool includeIfNotAlreadyIncluded(const QString &filename);
void AddScriptSection(const QString &section, const QByteArray &code, int skipStatement(QByteArray &modifiedScript, int pos);
int lineOffset);
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 processIfExpression(const QByteArray &codes, int currentLine,
const QByteArray &currentSection);
QByteArray findReplaceResult(const QByteArray &v);
asIScriptEngine *engine; asIScriptEngine *engine;
QList<ScriptData> modifiedScripts; QList<ScriptData> modifiedScripts;
@ -126,7 +154,10 @@ protected:
QStringList includedScripts; QStringList includedScripts;
QStringList definedWords; QHash<QString, QByteArray> definedWords;
private:
bool _isCodeCompleteMode = false;
}; };
#endif // ASPREPROCESSER_H #endif // ASPREPROCESSER_H

View File

@ -133,7 +133,7 @@ QString ClangFormatManager::formatCode(const QString &codes, bool &ok) {
.arg(m_clangStyle) .arg(m_clangStyle)
.arg(m_identWidth); .arg(m_identWidth);
auto ret = runClangFormat( auto ret = runClangFormat(
{style, QStringLiteral("--assume-filename=wing.cpp")}, codes, ok); {style, QStringLiteral("--assume-filename=wing.cs")}, codes, ok);
return ret; return ret;
} else { } else {
return runClangFormat({}, codes, ok); return runClangFormat({}, codes, ok);

View File

@ -1,84 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef CLICKCALLBACK_H
#define CLICKCALLBACK_H
#include "WingPlugin/iwingplugin.h"
#include "angelscript.h"
class ClickCallBack {
public:
ClickCallBack() {}
ClickCallBack(const WingHex::ClickedCallBack &b) : _call(b) {}
explicit ClickCallBack(asIScriptEngine *engine, asIScriptFunction *func)
: _engine(engine), _func(func) {
if (_engine && _func) {
_func->AddRef();
}
}
~ClickCallBack() {
if (_func) {
_func->Release();
}
}
public:
ClickCallBack &operator=(const WingHex::ClickedCallBack &_Right) {
*this = ClickCallBack(_Right);
return *this;
}
ClickCallBack &operator=(WingHex::ClickedCallBack &&_Right) {
*this = ClickCallBack(_Right);
return *this;
}
public:
explicit operator bool() const noexcept {
return _call || (_engine && _func);
}
void operator()(const QModelIndex &index) {
if (_call) {
_call(index);
} else {
if (_engine && _func) {
auto ctx = _engine->CreateContext();
if (ctx) {
auto r = ctx->Prepare(_func);
if (r >= 0) {
auto idx = index;
ctx->SetArgObject(0, &idx);
ctx->Execute();
}
ctx->Release();
}
}
}
}
private:
WingHex::ClickedCallBack _call;
asIScriptEngine *_engine = nullptr;
asIScriptFunction *_func = nullptr;
};
#endif // CLICKCALLBACK_H

View File

@ -36,6 +36,7 @@ QIcon CodeInfoTip::getDisplayIcon(Type type, CodeInfoVisibility vis) {
case Type::Group: case Type::Group:
return icon(ICON_NAMESPACE); return icon(ICON_NAMESPACE);
case Type::Class: case Type::Class:
case Type::TypeDef:
return icon(ICON_CLASS); return icon(ICON_CLASS);
case Type::ClsFunction: case Type::ClsFunction:
case Type::Function: case Type::Function:

View File

@ -36,6 +36,7 @@ public:
Variable, Variable,
Property = Variable, Property = Variable,
Enumerater, Enumerater,
TypeDef
}; };
enum CacheIndex { enum CacheIndex {
@ -78,6 +79,7 @@ public:
public: public:
QString name; QString name;
bool dontAddGlobal = false;
Type type = Type::Unknown; Type type = Type::Unknown;
QString nameSpace; QString nameSpace;
CodeInfoVisibility visualpo = CodeInfoVisibility::VISIBILITY_DEFAULT; CodeInfoVisibility visualpo = CodeInfoVisibility::VISIBILITY_DEFAULT;

View File

@ -151,6 +151,9 @@ void CTypeParser::initialize() {
ADD_TYPE(longlong, QMetaType::LongLong); ADD_TYPE(longlong, QMetaType::LongLong);
ADD_TYPE_U(ulonglong, QMetaType::ULongLong); ADD_TYPE_U(ulonglong, QMetaType::ULongLong);
using uint = unsigned int;
ADD_TYPE_U(uint, QMetaType::UInt);
using BOOL = bool; using BOOL = bool;
using BYTE = byte; using BYTE = byte;
using WORD = uint16; using WORD = uint16;
@ -242,6 +245,8 @@ void CTypeParser::initialize() {
#undef ADD_TYPE #undef ADD_TYPE
#undef ADD_TYPE_S #undef ADD_TYPE_S
base_types_ = type_maps_.keys();
} }
void CTypeParser::setIncludePaths(const QStringList &paths) { void CTypeParser::setIncludePaths(const QStringList &paths) {
@ -451,7 +456,7 @@ void CTypeParser::stripComments(QStringList &lines) const {
QStringLiteral("]"); QStringLiteral("]");
// search comment start // search comment start
while ((pos = line.indexOf(kSlash, pos)) != -1) { while ((pos = line.indexOf(char(kSlash), pos)) != -1) {
if (line.length() <= pos + 1) if (line.length() <= pos + 1)
break; // the 1st '/' is at the end of line, so not a comment break; // the 1st '/' is at the end of line, so not a comment
@ -627,7 +632,7 @@ TokenTypes CTypeParser::getTokenType(const QString &token) const {
return keywords_.value(token); return keywords_.value(token);
} else if (qualifiers_.contains(token)) { } else if (qualifiers_.contains(token)) {
return kQualifier; return kQualifier;
} else if (type_maps_.contains(token)) { } else if (base_types_.contains(token)) {
return kBasicDataType; return kBasicDataType;
} else if (struct_defs_.contains(token)) { } else if (struct_defs_.contains(token)) {
return kStructName; return kStructName;
@ -1065,7 +1070,7 @@ bool CTypeParser::parseDeclaration(const QString &line,
if (line.isEmpty()) { if (line.isEmpty()) {
return false; return false;
} }
if (line[line.length() - 1] != kSemicolon) if (line[line.length() - 1] != char(kSemicolon))
return false; return false;
QStringList tokens; QStringList tokens;
@ -1085,7 +1090,7 @@ bool CTypeParser::parseDeclaration(const QString &line,
return false; return false;
} }
if (tokens[++index].at(0) == kAsterisk) { if (tokens[++index].at(0) == char(kAsterisk)) {
decl.is_pointer = true; decl.is_pointer = true;
// size of a pointer is 4 types on a 32-bit system // size of a pointer is 4 types on a 32-bit system
length = length =
@ -1143,14 +1148,14 @@ bool CTypeParser::parseEnumDeclaration(const QString &line, int &last_value,
break; break;
case 2: case 2:
if (kComma != tokens[1].at(0)) { if (char(kComma) != tokens[1].at(0)) {
return false; return false;
} }
decl.second = ++last_value; decl.second = ++last_value;
break; break;
case 3: case 3:
if (kEqual != tokens[1].at(0)) { if (char(kEqual) != tokens[1].at(0)) {
return false; return false;
} }
@ -1166,7 +1171,8 @@ bool CTypeParser::parseEnumDeclaration(const QString &line, int &last_value,
break; break;
case 4: case 4:
if (!(kEqual == tokens[1].at(0) && kComma == tokens[3].at(0))) { if (!(char(kEqual) == tokens[1].at(0) &&
char(kComma) == tokens[3].at(0))) {
return false; return false;
} }
@ -1203,8 +1209,8 @@ bool CTypeParser::parseAssignExpression(const QString &line) {
// only 4 tokens for an assignment expression: var = number; // only 4 tokens for an assignment expression: var = number;
if (4 == splitLineIntoTokens(line, tokens) && if (4 == splitLineIntoTokens(line, tokens) &&
kEqual == tokens[1].at(tokens[1].length() - 1) && char(kEqual) == tokens[1].at(tokens[1].length() - 1) &&
kSemicolon == tokens[3].at(tokens[3].length() - 1) && char(kSemicolon) == tokens[3].at(tokens[3].length() - 1) &&
isNumericToken(tokens[2], number)) { isNumericToken(tokens[2], number)) {
const_defs_.insert(tokens[0], number); const_defs_.insert(tokens[0], number);
return true; return true;
@ -1239,7 +1245,7 @@ bool CTypeParser::parsePreProcDirective(const QString &src, qsizetype &pos) {
} }
// only handle header file included with "" // only handle header file included with ""
if (kQuotation == token[token.length() - 1]) { if (char(kQuotation) == token[token.length() - 1]) {
// get included header file name // get included header file name
if (!getNextToken(src, pos, token, false)) { if (!getNextToken(src, pos, token, false)) {
return false; return false;
@ -1366,7 +1372,7 @@ bool CTypeParser::parseStructUnion(const bool is_struct, const bool is_typedef,
if (is_typedef) { if (is_typedef) {
// format 1 // format 1
if (!(getNextToken(src, pos, next_token) && if (!(getNextToken(src, pos, next_token) &&
kSemicolon == next_token.at(0))) { char(kSemicolon) == next_token.at(0))) {
return false; return false;
} }
@ -1387,7 +1393,7 @@ bool CTypeParser::parseStructUnion(const bool is_struct, const bool is_typedef,
type_maps_[type_name] = type_maps_[type_alias]; type_maps_[type_name] = type_maps_[type_alias];
} }
} else { // non-typedef } else { // non-typedef
if (kSemicolon == token.at(0)) { if (char(kSemicolon) == token.at(0)) {
// format 2 // format 2
is_decl = false; is_decl = false;
if (type_name.isEmpty()) { if (type_name.isEmpty()) {
@ -1542,7 +1548,7 @@ bool CTypeParser::parseEnum(const bool is_typedef, const QString &src,
if (is_typedef) { if (is_typedef) {
// format 1 // format 1
if (!(getNextToken(src, pos, next_token) && if (!(getNextToken(src, pos, next_token) &&
kSemicolon == next_token.at(0))) { char(kSemicolon) == next_token.at(0))) {
return false; return false;
} }
@ -1559,7 +1565,7 @@ bool CTypeParser::parseEnum(const bool is_typedef, const QString &src,
; ;
} }
} else { // non-typedef } else { // non-typedef
if (kSemicolon == token.at(0)) { if (char(kSemicolon) == token.at(0)) {
// format 2 // format 2
is_decl = false; is_decl = false;
if (type_name.isEmpty()) { if (type_name.isEmpty()) {

View File

@ -211,6 +211,9 @@ private:
/// @note All enum types have fixed size, so they're not stored /// @note All enum types have fixed size, so they're not stored
QHash<QString, QPair<QMetaType::Type, qsizetype>> type_maps_; QHash<QString, QPair<QMetaType::Type, qsizetype>> type_maps_;
/// basic types
QStringList base_types_;
/// unsigned types /// unsigned types
QStringList unsigned_types_; QStringList unsigned_types_;

View File

@ -1,6 +1,8 @@
#include "inspectqtloghelper.h" #include "inspectqtloghelper.h"
#include "utilities.h" #include "utilities.h"
#include <QMenu>
#include <iostream> #include <iostream>
#define INFOLOG(msg) "<font color=\"green\">" + msg + "</font>" #define INFOLOG(msg) "<font color=\"green\">" + msg + "</font>"

View File

@ -17,10 +17,10 @@
#include "pluginsystem.h" #include "pluginsystem.h"
#include "AngelScript/sdk/angelscript/source/as_builder.h" #include "AngelScript/sdk/angelscript/source/as_builder.h"
#include "QJsonModel/include/QJsonModel.hpp"
#include "Qt-Advanced-Docking-System/src/DockAreaWidget.h" #include "Qt-Advanced-Docking-System/src/DockAreaWidget.h"
#include "class/languagemanager.h" #include "class/languagemanager.h"
#include "class/logger.h" #include "class/logger.h"
#include "class/scriptmachine.h"
#include "class/settingmanager.h" #include "class/settingmanager.h"
#include "class/skinmanager.h" #include "class/skinmanager.h"
#include "class/wingcstruct.h" #include "class/wingcstruct.h"
@ -32,10 +32,11 @@
#include "dialog/colorpickerdialog.h" #include "dialog/colorpickerdialog.h"
#include "dialog/framelessdialogbase.h" #include "dialog/framelessdialogbase.h"
#include "dialog/mainwindow.h" #include "dialog/mainwindow.h"
#include "model/qjsontablemodel.h"
#include <QDir> #include <QDir>
#include <QFileInfoList> #include <QFileInfoList>
#include <QJsonArray>
#include <QJsonDocument>
#include <QMessageBox> #include <QMessageBox>
#include <QPluginLoader> #include <QPluginLoader>
#include <QScopeGuard> #include <QScopeGuard>
@ -1786,99 +1787,6 @@ bool PluginSystem::closeAllFiles(QObject *sender) {
return true; return true;
} }
bool PluginSystem::dataVisualText(QObject *sender, const QString &data,
const QString &title) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
_win->m_infotxt->setProperty("__TITLE__", title);
_win->m_infotxt->setText(data);
return true;
}
bool PluginSystem::dataVisualTextList(QObject *sender, const QStringList &data,
const QString &title,
ClickedCallBack clicked,
ClickedCallBack dblClicked) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
return updateTextList_API(data, title, clicked, dblClicked);
}
bool PluginSystem::dataVisualTextTree(QObject *sender, const QString &json,
const QString &title,
ClickedCallBack clicked,
ClickedCallBack dblClicked) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
return updateTextTree_API(json, title, clicked, dblClicked);
}
bool PluginSystem::dataVisualTextTable(QObject *sender, const QString &json,
const QStringList &headers,
const QStringList &headerNames,
const QString &title,
ClickedCallBack clicked,
ClickedCallBack dblClicked) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
return updateTextTable_API(json, headers, headerNames, title, clicked,
dblClicked);
}
bool PluginSystem::dataVisualTextListByModel(QObject *sender,
QAbstractItemModel *model,
const QString &title,
ClickedCallBack clicked,
ClickedCallBack dblClicked) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
if (model) {
auto oldmodel = _win->m_infolist->model();
if (oldmodel) {
oldmodel->deleteLater();
}
_win->m_infolist->setProperty("__TITLE__", title);
_win->m_infolist->setModel(model);
_win->m_infoclickfn = clicked;
_win->m_infodblclickfn = dblClicked;
return true;
}
return false;
}
bool PluginSystem::dataVisualTextTreeByModel(QObject *sender,
QAbstractItemModel *model,
const QString &title,
ClickedCallBack clicked,
ClickedCallBack dblClicked) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
if (model) {
auto oldmodel = _win->m_infotree->model();
if (oldmodel) {
oldmodel->deleteLater();
}
_win->m_infotree->setProperty("__TITLE__", title);
_win->m_infotree->setModel(model);
_win->m_infotreeclickfn = clicked;
_win->m_infotreedblclickfn = dblClicked;
return true;
}
return false;
}
bool PluginSystem::checkErrAllAllowAndReport(QObject *sender, bool PluginSystem::checkErrAllAllowAndReport(QObject *sender,
const char *func) { const char *func) {
auto p = qobject_cast<WingHex::IWingPlugin *>(sender); auto p = qobject_cast<WingHex::IWingPlugin *>(sender);
@ -1903,29 +1811,6 @@ IWingPlugin *PluginSystem::checkPluginAndReport(QObject *sender,
return p; return p;
} }
bool PluginSystem::dataVisualTextTableByModel(QObject *sender,
QAbstractItemModel *model,
const QString &title,
ClickedCallBack clicked,
ClickedCallBack dblClicked) {
auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr || !checkThreadAff()) {
return false;
}
if (model) {
auto oldmodel = _win->m_infotable->model();
if (oldmodel) {
oldmodel->deleteLater();
}
_win->m_infotable->setProperty("__TITLE__", title);
_win->m_infotable->setModel(model);
_win->m_infotableclickfn = clicked;
_win->m_infotabledblclickfn = dblClicked;
return true;
}
return false;
}
ErrFile PluginSystem::saveAsCurrent(QObject *sender, const QString &savename) { ErrFile PluginSystem::saveAsCurrent(QObject *sender, const QString &savename) {
auto plg = checkPluginAndReport(sender, __func__); auto plg = checkPluginAndReport(sender, __func__);
if (plg == nullptr) { if (plg == nullptr) {
@ -2955,6 +2840,10 @@ void PluginSystem::checkDirRootSafe(const QDir &dir) {
} }
void PluginSystem::registerFns(IWingPlugin *plg) { void PluginSystem::registerFns(IWingPlugin *plg) {
if (_angelplg == nullptr) {
return;
}
Q_ASSERT(plg); Q_ASSERT(plg);
auto fns = plg->registeredScriptFns(); auto fns = plg->registeredScriptFns();
if (fns.isEmpty()) { if (fns.isEmpty()) {
@ -3027,6 +2916,10 @@ void PluginSystem::registerFns(IWingPlugin *plg) {
} }
void PluginSystem::registerUnSafeFns(IWingPlugin *plg) { void PluginSystem::registerUnSafeFns(IWingPlugin *plg) {
if (_angelplg == nullptr) {
return;
}
Q_ASSERT(plg); Q_ASSERT(plg);
auto fns = plg->registeredScriptUnsafeFns(); auto fns = plg->registeredScriptUnsafeFns();
@ -3233,8 +3126,8 @@ void PluginSystem::applyFunctionTables(IWingPluginBase *plg,
plg->setProperty("__CALL_POINTER__", quintptr(this)); plg->setProperty("__CALL_POINTER__", quintptr(this));
} }
QString PluginSystem::type2AngelScriptString(IWingPlugin::MetaType type, QString PluginSystem::type2AngelScriptString(uint type, bool isArg,
bool isArg, bool noModifier) { bool noModifier) {
auto isArray = !!(type & WingHex::IWingPlugin::Array); auto isArray = !!(type & WingHex::IWingPlugin::Array);
auto isList = !!(type & WingHex::IWingPlugin::List); auto isList = !!(type & WingHex::IWingPlugin::List);
auto isContainer = isArray || isList; auto isContainer = isArray || isList;
@ -3715,77 +3608,6 @@ void PluginSystem::registerMarcoDevice(IWingDevice *plg) {
_scriptMarcos.append(sep + id + sep); _scriptMarcos.append(sep + id + sep);
} }
bool PluginSystem::updateTextList_API(const QStringList &data,
const QString &title,
const ClickCallBack &click,
const ClickCallBack &dblclick) {
auto oldmodel = _win->m_infolist->model();
if (oldmodel) {
oldmodel->deleteLater();
}
_win->m_infolist->setProperty("__TITLE__", title);
auto model = new QStringListModel(data);
_win->m_infolist->setModel(model);
_win->m_infoclickfn = click;
_win->m_infodblclickfn = dblclick;
return true;
}
bool PluginSystem::updateTextTree_API(const QString &json, const QString &title,
const ClickCallBack &click,
const ClickCallBack &dblclick) {
auto oldmodel = _win->m_infotree->model();
if (oldmodel) {
oldmodel->deleteLater();
}
_win->m_infotree->setProperty("__TITLE__", title);
auto model = new QJsonModel;
if (model->loadJson(json.toUtf8())) {
_win->m_infotree->setModel(model);
_win->m_infotreeclickfn = click;
_win->m_infotreedblclickfn = dblclick;
return true;
}
return false;
}
bool PluginSystem::updateTextTable_API(const QString &json,
const QStringList &headers,
const QStringList &headerNames,
const QString &title,
const ClickCallBack &click,
const ClickCallBack &dblclick) {
auto oldmodel = _win->m_infotable->model();
if (oldmodel) {
oldmodel->deleteLater();
}
QJsonTableModel::Header header;
if (headers.size() > headerNames.size()) {
for (auto &name : headers) {
QJsonTableModel::Heading heading;
heading["index"] = name;
heading["title"] = name;
header.append(heading);
}
} else {
auto np = headerNames.cbegin();
for (auto p = headers.cbegin(); p != headers.cend(); ++p, ++np) {
QJsonTableModel::Heading heading;
heading["index"] = *p;
heading["title"] = *np;
header.append(heading);
}
}
_win->m_infotable->setProperty("__TITLE__", title);
auto model = new QJsonTableModel(header);
model->setJson(QJsonDocument::fromJson(json.toUtf8()));
_win->m_infotable->setModel(model);
_win->m_infotableclickfn = click;
_win->m_infotabledblclickfn = dblclick;
return true;
}
bool PluginSystem::checkThreadAff() { bool PluginSystem::checkThreadAff() {
if (QThread::currentThread() != qApp->thread()) { if (QThread::currentThread() != qApp->thread()) {
Logger::warning(tr("Not allowed operation in non-UI thread")); Logger::warning(tr("Not allowed operation in non-UI thread"));
@ -3886,6 +3708,8 @@ void PluginSystem::loadAllPlugin() {
} }
} }
Logger::newLine();
// loading finished, delete the checking engine // loading finished, delete the checking engine
finalizeCheckingEngine(); finalizeCheckingEngine();
} }

View File

@ -32,7 +32,6 @@
#include <QVariant> #include <QVariant>
#include "WingPlugin/iwingdevice.h" #include "WingPlugin/iwingdevice.h"
#include "class/clickcallback.h"
#include "class/wingangelapi.h" #include "class/wingangelapi.h"
#include "control/editorview.h" #include "control/editorview.h"
@ -176,8 +175,8 @@ public:
static QString getPUID(IWingPluginBase *p); static QString getPUID(IWingPluginBase *p);
static QString type2AngelScriptString(IWingPlugin::MetaType type, static QString type2AngelScriptString(uint type, bool isArg,
bool isArg, bool noModifier = false); bool noModifier = false);
private: private:
void loadExtPlugin(); void loadExtPlugin();
@ -258,18 +257,6 @@ private:
void registerPluginDockWidgets(IWingPluginBase *p); void registerPluginDockWidgets(IWingPluginBase *p);
void registerPluginPages(IWingPluginBase *p); void registerPluginPages(IWingPluginBase *p);
public:
bool updateTextList_API(const QStringList &data, const QString &title,
const ClickCallBack &click,
const ClickCallBack &dblclick);
bool updateTextTree_API(const QString &json, const QString &title,
const ClickCallBack &click,
const ClickCallBack &dblclick);
bool updateTextTable_API(const QString &json, const QStringList &headers,
const QStringList &headerNames,
const QString &title, const ClickCallBack &click,
const ClickCallBack &dblclick);
public: public:
// fpr crash checking // fpr crash checking
QString currentLoadingPlugin() const; QString currentLoadingPlugin() const;
@ -735,41 +722,6 @@ public:
// extension // extension
WING_SERVICE bool closeAllFiles(QObject *sender); WING_SERVICE bool closeAllFiles(QObject *sender);
public:
WING_SERVICE bool dataVisualText(QObject *sender, const QString &data,
const QString &title);
WING_SERVICE bool dataVisualTextList(QObject *sender,
const QStringList &data,
const QString &title,
WingHex::ClickedCallBack clicked,
WingHex::ClickedCallBack dblClicked);
WING_SERVICE bool dataVisualTextTree(QObject *sender, const QString &json,
const QString &title,
WingHex::ClickedCallBack clicked,
WingHex::ClickedCallBack dblClicked);
WING_SERVICE bool dataVisualTextTable(QObject *sender, const QString &json,
const QStringList &headers,
const QStringList &headerNames,
const QString &title,
WingHex::ClickedCallBack clicked,
WingHex::ClickedCallBack dblClicked);
// API for Qt Plugin Only
WING_SERVICE bool dataVisualTextListByModel(
QObject *sender, QAbstractItemModel *model, const QString &title,
WingHex::ClickedCallBack clicked, WingHex::ClickedCallBack dblClicked);
WING_SERVICE bool dataVisualTextTableByModel(
QObject *sender, QAbstractItemModel *model, const QString &title,
WingHex::ClickedCallBack clicked, WingHex::ClickedCallBack dblClicked);
WING_SERVICE bool dataVisualTextTreeByModel(
QObject *sender, QAbstractItemModel *model, const QString &title,
WingHex::ClickedCallBack clicked, WingHex::ClickedCallBack dblClicked);
private: private:
WingHex::IWingPlugin *checkPluginAndReport(QObject *sender, WingHex::IWingPlugin *checkPluginAndReport(QObject *sender,
const char *func); const char *func);

File diff suppressed because it is too large Load Diff

View File

@ -24,11 +24,10 @@
#include <QMap> #include <QMap>
#include <QString> #include <QString>
// This class is the modification of as_parser. // This class comes from as_parser.h .
// You can modified it to support more features. // You can modified it to support more features.
/** It's a complex thing to fully support AngelScript code intellisense. /** It's a complex thing to fully support AngelScript code intellisense.
** I just support basic code completion like local or global ** I just support basic code completion.
* variables/functions.
** If you are interested in implement a well-featured intellisense like ** If you are interested in implement a well-featured intellisense like
* Qt creator or Visual Studio, PRs are welcomed !!! * Qt creator or Visual Studio, PRs are welcomed !!!
*/ */
@ -42,195 +41,192 @@ public:
public: public:
enum class SymbolType { enum class SymbolType {
Invalid, Invalid,
FnDecl, Variable, // variable or property in class
Import, Enum, // an enum
Value, // a common value Class, // a class type
Variable, // a variable Function, // a function
Enum, // an enum TypeDef, // a typedef
Class, // a class type FnDef, // a funcdef
Function, // a function Interface, // an interface
TypeDef, // a typedef Import, // import but not supported
FnDef, // a funcdef
Property, // a property
}; };
enum class Visiblity { Public, Private, Protected }; enum class Visiblity { Public, Private, Protected };
/**
struct Symbol; * @brief The CodeSegment class
*/
struct CodeSegment { struct CodeSegment {
bool valid = false; QByteArrayList scope;
// QByteArrayList ns;
QByteArray ret;
QByteArray name; QByteArray name;
qsizetype nameInSrc = -1; SymbolType type = QAsCodeParser::SymbolType::Invalid;
QList<Symbol> args; qsizetype offset = -1;
QByteArray code; QByteArray codes;
bool isValid() const { return valid; } QByteArrayList additonalInfos; // for other additonal infos
public:
inline bool isValid() const {
return offset >= 0 && type != SymbolType::Invalid;
}
inline qsizetype end() const {
if (offset < 0) {
return -1;
}
return offset + codes.length();
}
inline qsizetype length() const { return codes.length(); }
inline bool hasCodes() const { return !codes.isEmpty(); }
}; };
struct Symbol { struct Symbol {
SymbolType type = SymbolType::Invalid; SymbolType symtype = QAsCodeParser::SymbolType::Invalid;
QString name; QByteArrayList scope;
qsizetype nameInSrc = -1; QByteArray name;
QString typeStr; QByteArray type;
Visiblity vis = Visiblity::Public; int offset = -1;
QList<Symbol> content; Visiblity vis = QAsCodeParser::Visiblity::Public;
QByteArray additonalInfo; // for other additonal info
// QByteArrayList ns; // namespaces QByteArrayList inherit;
QMap<qsizetype, CodeSegment> codesegs; // used in class QList<Symbol> children;
// size_t scope = 0; // 0 for all
bool isValid() const { return type != SymbolType::Invalid; }
}; };
using SymbolTable = QMap<size_t, Symbol>; public:
// First, we should parse and split the code into segments
QList<QAsCodeParser::CodeSegment> parse(const QByteArray &codes);
private: // Then, we can deep parsing for code completion
// QMap< offset , CodeSegment> QList<Symbol> parseIntell(qsizetype offset,
QMap<qsizetype, CodeSegment> m_segs; // global functions const QList<QAsCodeParser::CodeSegment> &segs);
// so, a helper function?
QList<Symbol> parseAndIntell(qsizetype offset, const QByteArray &codes);
public: public:
SymbolTable parse(const QByteArray &codes); static eTokenType getToken(asIScriptEngine *engine, const char *string,
size_t stringLength, size_t *tokenLength);
SymbolTable parseIntell(qsizetype offset, const QByteArray &codes);
private: private:
void ParseScript(bool inBlock); QList<QAsCodeParser::CodeSegment> parseScript(bool inBlock);
void skipCodeBlock();
QByteArray getSymbolString(const sToken &t); QByteArray getSymbolString(const sToken &t);
QByteArrayList getRealNamespace(const QByteArrayList &ns);
// parse tokens
sToken ParseIdentifier();
sToken ParseToken(int token);
sToken ParseRealType();
sToken ParseDataType(bool allowVariableType = false,
bool allowAuto = false);
sToken ParseOneOf(int *tokens, int count);
sToken ParseType(bool allowConst, bool allowVariableType = false,
bool allowAuto = false);
// Statements // Statements
sToken SuperficiallyParseVarInit(); void superficiallyParseVarInit();
sToken superficiallyParseStatementBlock();
void superficiallyParseExpression();
void superficiallyParseTemplateList();
// parse and get symbols void parseMethodAttributes();
Symbol ParseImport();
void ParseEnumeration();
void ParseTypedef();
void ParseClass();
void ParseMixin();
void ParseInterface();
Symbol ParseFuncDef();
void ParseNamespace();
void ParseReturn();
void ParseBreak();
void ParseContinue();
void ParseTryCatch();
void ParseIf();
void ParseLambda();
void ParseStatement();
CodeSegment ParseFunction(bool isMethod = false);
void ParseExpressionStatement();
void ParseListPattern();
void ParseStatementBlock();
void ParseAssignment();
void ParseAssignOperator();
void ParseSwitch();
void ParseCase();
void ParseFor();
void ParseWhile();
void ParseDoWhile();
void ParseCondition();
void ParseExpression();
void ParseExprTerm();
void ParseExprOperator();
void ParseExprPreOp();
void ParseExprPostOp();
void ParseExprValue();
QByteArrayList ParseOptionalScope();
Symbol ParseVirtualPropertyDecl(bool isMethod, bool isInterface);
QList<Symbol> ParseParameterList();
// parse but not get symbols
void ParseTypeMod(bool isParam);
void ParseFunctionCall();
void SuperficiallyParseStatementBlock();
void ParseInitList();
void ParseCast();
void ParseVariableAccess();
void ParseConstructCall();
void ParseConstant();
private: private:
void Reset(); CodeSegment parseEnumeration();
CodeSegment parseTypedef();
bool IsVarDecl(); CodeSegment parseClass();
bool IsVirtualPropertyDecl(); CodeSegment parseMixin();
bool IsFuncDecl(bool isMethod); CodeSegment parseInterface();
bool IsLambda(); CodeSegment parseFuncDef();
bool IsFunctionCall(); CodeSegment parseFunction();
CodeSegment parseFunctionMethod(Visiblity &vis);
void GetToken(sToken *token);
void RewindTo(const sToken *token);
void RewindErrorTo(sToken *token);
void SetPos(size_t pos);
bool IsRealType(int tokenType);
bool IdentifierIs(const sToken &t, const char *str);
bool IsDataType(const sToken &token);
private: private:
bool CheckTemplateType(const sToken &t); // parse tokens
bool ParseTemplTypeList(bool required = true); sToken parseIdentifier();
void ParseMethodAttributes(); sToken parseToken(int token);
sToken parseRealType();
sToken parseDataType(bool allowVariableType = false,
bool allowAuto = false);
sToken parseOneOf(int *tokens, int count);
void ParseArgList(bool withParenthesis = true); void parseNamespace();
void SuperficiallyParseExpression();
private: private:
bool FindTokenAfterType(sToken &nextToken); // deep parsing
bool FindIdentifierAfterScope(sToken &nextToken); QList<Symbol> parseEnumerationContent(const QByteArrayList &ns,
bool IsConstant(int tokenType); const QByteArray &name,
bool IsOperator(int tokenType); const QByteArray &code);
bool IsPreOperator(int tokenType); Symbol parseTypedefContent(const QByteArrayList &ns,
bool IsPostOperator(int tokenType); const QByteArray &code);
bool IsAssignOperator(int tokenType);
bool DoesTypeExist(const QString &t); QList<Symbol> parseGlobalVarDecls(const QByteArrayList &ns,
const QByteArray &code);
Symbol ParseFunctionDefinition(); QByteArrayList parseOptionalScope();
QList<Symbol> ParseDeclaration(bool isClassProp = false, QList<Symbol> parseDeclaration(qsizetype end, const QByteArrayList &ns,
bool isClassProp = false,
bool isGlobalVar = false); bool isGlobalVar = false);
Symbol ParseInterfaceMethod(); QByteArray parseType(bool allowConst, bool allowVariableType = false,
bool allowAuto = false);
void ParseStringConstant(); Symbol parseFuncDefContent(const QByteArrayList &ns,
const QByteArray &code);
Symbol parseFuncDefContent(const QByteArrayList &ns);
QPair<QByteArrayList, QList<Symbol>>
parseClassContent(qsizetype offset, const QByteArrayList &ns,
const QByteArray &code);
QPair<QByteArrayList, QList<Symbol>>
parseInterfaceContent(qsizetype offset, const QByteArrayList &ns,
const QByteArray &code);
QList<Symbol> parseStatementBlock(const QByteArrayList &ns,
const QByteArray &code, qsizetype end);
private: private:
bool errorWhileParsing; Symbol parseVirtualPropertyDecl(bool isMethod, bool isInterface);
bool isSyntaxError; QList<Symbol> parseParameterListContent();
bool checkValidTypes;
bool isParsingAppInterface; // parse but not get symbols
void parseTypeMod(bool isParam);
private:
void reset();
bool isVarDecl();
bool isVirtualPropertyDecl();
bool isFuncDecl(bool isMethod);
void getToken(sToken *token);
void rewindTo(const sToken *token);
void rewindErrorTo(sToken *token);
void setPos(size_t pos);
bool isPrimType(int tokenType);
bool identifierIs(const sToken &t, const char *str);
bool isDataType(const sToken &token);
private:
bool checkTemplateType(const sToken &t);
private:
bool findTokenAfterType(sToken &nextToken);
bool typeExist(const QString &t);
Symbol parseInterfaceMethod();
private:
bool _errorWhileParsing;
bool _isSyntaxError;
bool _checkValidTypes;
bool _isParsingAppInterface;
asCScriptEngine *engine; asCScriptEngine *engine;
// size_t _curscope = 0; QByteArray _code;
SymbolTable _symtable;
QByteArray code; sToken _lastToken;
QByteArray tempString; // Used for reduzing amount of dynamic allocations size_t _sourcePos;
sToken lastToken; QByteArrayList currentNs;
size_t sourcePos;
}; };
#endif // QASCODEPARSER_H #endif // QASCODEPARSER_H

View File

@ -1,157 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "scriptconsolemachine.h"
#include <QRegularExpression>
#include <QTextStream>
ScriptConsoleMachine::ScriptConsoleMachine(
std::function<QString(void)> &getInputFn, QObject *parent)
: ScriptMachine(getInputFn, parent) {
if (!ScriptConsoleMachine::configureEngine(engine())) {
destoryMachine();
}
if (engine()) {
_model = new ScriptObjModel(engine(), debugger(), this);
}
}
ScriptConsoleMachine::~ScriptConsoleMachine() {}
bool ScriptConsoleMachine::executeCode(const QString &code) {
return execString(engine(), code);
}
ScriptObjModel *ScriptConsoleMachine::model() const { return _model; }
bool ScriptConsoleMachine::configureEngine(asIScriptEngine *engine) {
_clsfn = std::bind(&ScriptConsoleMachine::onClearConsole, this);
auto r = engine->RegisterGlobalFunction(
"void clear()", asMETHOD(decltype(_clsfn), operator()),
asCALL_THISCALL_ASGLOBAL, &_clsfn);
Q_ASSERT(r >= 0);
return r >= 0;
}
bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
const QString &code) {
auto mod = engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS);
if (code.startsWith(QStringLiteral("addvar "))) {
auto varcmd = code.mid(7) + QStringLiteral(";");
if (varcmd.length() == 1) {
MessageInfo info;
info.message = tr("EmptyDecl");
emit onOutput(MessageType::Error, info);
return false;
}
auto ret = mod->CompileGlobalVar("addvar", varcmd.toUtf8(), 0) >= 0;
_model->updateData();
return ret;
} else if (code.startsWith(QStringLiteral("rmvar "))) {
if (mod == nullptr || mod->GetGlobalVarCount() == 0) {
return false;
}
// remove the tailing semi-colons
static QRegularExpression re(QStringLiteral(";+$"));
auto varcmd = code.mid(6).remove(re);
for (auto &var : varcmd.split(' ', Qt::SkipEmptyParts)) {
int index = mod->GetGlobalVarIndexByName(var.toUtf8());
if (index >= 0) {
mod->RemoveGlobalVar(index);
}
}
_model->updateData();
return true;
} else if (code.startsWith(QStringLiteral("lsfn"))) {
if (code.trimmed().length() != 4) {
return false;
}
QString str;
QTextStream s(&str);
asUINT n;
// List the application registered functions
s << tr("Application functions:") << Qt::endl;
for (n = 0; n < engine->GetGlobalFunctionCount(); n++) {
asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n);
// Skip the functions that start with _ as these are not meant to be
// called explicitly by the user
if (func->GetName()[0] != '_')
s << QStringLiteral(" ") << func->GetDeclaration() << Qt::endl;
}
// List the user functions in the module
if (mod) {
s << Qt::endl;
s << tr("User functions:") << Qt::endl;
for (n = 0; n < mod->GetFunctionCount(); n++) {
asIScriptFunction *func = mod->GetFunctionByIndex(n);
s << QStringLiteral(" ") << func->GetDeclaration() << Qt::endl;
}
}
MessageInfo info;
info.message = str;
emit onOutput(MessageType::Info, info);
return true;
} else if (code.startsWith(QStringLiteral("lsvar"))) {
if (code.trimmed().length() != 5) {
return false;
}
QString str;
QTextStream s(&str);
asUINT n;
// List the application registered variables
s << tr("Application variables:") << Qt::endl;
for (n = 0; n < engine->GetGlobalPropertyCount(); n++) {
const char *name;
int typeId;
bool isConst;
engine->GetGlobalPropertyByIndex(n, &name, 0, &typeId, &isConst);
auto decl =
isConst ? QStringLiteral(" const ") : QStringLiteral(" ");
decl += engine->GetTypeDeclaration(typeId);
decl += QStringLiteral(" ");
decl += name;
s << decl << Qt::endl;
}
// List the user variables in the module
if (mod) {
s << Qt::endl;
s << tr("User variables:") << Qt::endl;
for (n = 0; n < (asUINT)mod->GetGlobalVarCount(); n++) {
s << QStringLiteral(" ") << mod->GetGlobalVarDeclaration(n)
<< Qt::endl;
}
}
MessageInfo info;
info.message = str;
emit onOutput(MessageType::Info, info);
return true;
} else {
return ScriptMachine::executeCode(code);
}
}

View File

@ -1,50 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef SCRIPTCONSOLEMACHINE_H
#define SCRIPTCONSOLEMACHINE_H
#include "model/scriptobjmodel.h"
#include "scriptmachine.h"
class ScriptConsoleMachine : public ScriptMachine {
Q_OBJECT
public:
explicit ScriptConsoleMachine(std::function<QString()> &getInputFn,
QObject *parent = nullptr);
virtual ~ScriptConsoleMachine();
virtual bool executeCode(const QString &code) override;
ScriptObjModel *model() const;
signals:
void onClearConsole();
protected:
virtual bool configureEngine(asIScriptEngine *engine) override;
private:
bool execString(asIScriptEngine *engine, const QString &code);
private:
ScriptObjModel *_model = nullptr;
std::function<void(void)> _clsfn;
};
#endif // SCRIPTCONSOLEMACHINE_H

File diff suppressed because it is too large Load Diff

View File

@ -18,27 +18,40 @@
#ifndef SCRIPTMACHINE_H #ifndef SCRIPTMACHINE_H
#define SCRIPTMACHINE_H #define SCRIPTMACHINE_H
#include "AngelScript/sdk/add_on/contextmgr/contextmgr.h"
#include "AngelScript/sdk/angelscript/include/angelscript.h" #include "AngelScript/sdk/angelscript/include/angelscript.h"
#include "class/aspreprocesser.h" #include "class/aspreprocesser.h"
#include "asdebugger.h" #include "asdebugger.h"
#include "class/ascontextmgr.h"
#include <QObject> #include <QObject>
#include <QQueue>
class CScriptArray;
class ScriptMachine : public QObject { class ScriptMachine : public QObject {
Q_OBJECT Q_OBJECT
private: private:
using TranslateFunc = std::function<QString(const QStringList &)>; using TranslateFunc = std::function<QString(const QStringList &)>;
public:
// we have three console modes
enum ConsoleMode {
Interactive = 1, // in a shell
Scripting, // in scripting dialog
Background, // run codes from other way
};
public: public:
enum class MessageType { Info, Warn, Error, Print }; enum class MessageType { Info, Warn, Error, Print };
struct MessageInfo { struct MessageInfo {
ConsoleMode mode = ConsoleMode::Background;
QString section; QString section;
int row = -1; int row = -1;
int col = -1; int col = -1;
asEMsgType type = asEMsgType::asMSGTYPE_INFORMATION; MessageType type = MessageType::Info;
QString message; QString message;
}; };
@ -78,29 +91,54 @@ public:
Q_ENUM(asEContextState) Q_ENUM(asEContextState)
public: public:
explicit ScriptMachine(const std::function<QString()> &getInputFn, struct RegCallBacks {
QObject *parent = nullptr); std::function<QString()> getInputFn;
std::function<void()> clearFn;
std::function<void(const ScriptMachine::MessageInfo &)> printMsgFn;
};
virtual ~ScriptMachine(); private:
explicit ScriptMachine();
Q_DISABLE_COPY_MOVE(ScriptMachine)
bool inited(); private:
asIScriptModule *createModule(ConsoleMode mode);
asIScriptModule *createModuleIfNotExist(ConsoleMode mode);
bool isModuleExists(ConsoleMode mode);
bool isRunning() const; public:
asIScriptModule *module(ConsoleMode mode);
static ScriptMachine &instance();
void destoryMachine();
public:
bool init();
bool isInited() const;
bool isRunning(ConsoleMode mode) const;
static void registerEngineAddon(asIScriptEngine *engine);
static void registerEngineAssert(asIScriptEngine *engine);
static void registerEngineClipboard(asIScriptEngine *engine);
void registerCallBack(ConsoleMode mode, const RegCallBacks &callbacks);
public:
asDebugger *debugger() const; asDebugger *debugger() const;
asIScriptEngine *engine() const; asIScriptEngine *engine() const;
bool insteadFoundDisabled() const; void outputMessage(const MessageInfo &info);
void setInsteadFoundDisabled(bool newInsteadFoundDisabled);
static void registerEngineAddon(asIScriptEngine *engine);
static void registerEngineAssert(asIScriptEngine *engine);
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);
static void clip_setText(const QString &text);
static void clip_setBinary(const CScriptArray &array);
static QString clip_getText();
static CScriptArray *clip_getBinary();
static void scriptThrow(const QString &msg); static void scriptThrow(const QString &msg);
static QString scriptGetExceptionInfo(); static QString scriptGetExceptionInfo();
@ -109,27 +147,28 @@ public:
public: public:
// debug or release? // debug or release?
bool isDebugMode() const; bool isDebugMode(ConsoleMode mode = Scripting);
void setDebugMode(bool isDbg);
public slots: public slots:
virtual bool executeCode(const QString &code); bool executeCode(ConsoleMode mode, const QString &code);
virtual bool executeScript(const QString &script, bool isInDebug = false); // only scripting mode can be debugged
bool executeScript(ConsoleMode mode, const QString &script,
bool isInDebug = false, int *retCode = nullptr);
int evaluateDefine(const QString &code, bool &result);
void abortDbgScript();
void abortScript(ConsoleMode mode);
void abortScript(); void abortScript();
private:
bool execute(const QString &code, bool isInDebug = false);
protected: protected:
virtual bool configureEngine(asIScriptEngine *engine); bool configureEngine();
QString getCallStack(asIScriptContext *context); QString getCallStack(asIScriptContext *context);
void destoryMachine();
private: private:
void print(void *ref, int typeId); static void print(asIScriptGeneric *args);
static void println(asIScriptGeneric *args);
QString getInput(); QString getInput();
@ -138,6 +177,10 @@ private:
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);
@ -166,21 +209,19 @@ private:
Q_DECL_UNUSED void translation(); Q_DECL_UNUSED void translation();
signals: signals:
void onOutput(MessageType type, const MessageInfo &message);
void onDebugFinished(); void onDebugFinished();
private: private:
asIScriptEngine *_engine = nullptr; asIScriptEngine *_engine = nullptr;
asDebugger *_debugger = nullptr; asDebugger *_debugger = nullptr;
asContextMgr *_ctxMgr = nullptr; CContextMgr *_ctxMgr = nullptr;
QVector<asIScriptContext *> _ctxPool;
std::function<void(void *ref, int typeId)> _printFn; QQueue<asIScriptContext *> _ctxPool;
QVector<asITypeInfo *> _rtypes; QVector<asITypeInfo *> _rtypes;
std::function<QString(void)> _getInputFn; QMap<ConsoleMode, RegCallBacks> _regcalls;
QMap<ConsoleMode, asIScriptContext *> _ctx;
bool m_insteadFoundDisabled = false; ConsoleMode _curMsgMode = ConsoleMode::Background;
}; };
Q_DECLARE_METATYPE(ScriptMachine::MessageInfo) Q_DECLARE_METATYPE(ScriptMachine::MessageInfo)

View File

@ -25,6 +25,7 @@
#include <QJsonObject> #include <QJsonObject>
#include <QMenu> #include <QMenu>
#include "scriptmachine.h"
#include "settingmanager.h" #include "settingmanager.h"
#include "utilities.h" #include "utilities.h"
#include "wingmessagebox.h" #include "wingmessagebox.h"
@ -50,7 +51,7 @@ ScriptManager::ScriptManager() : QObject() {
refresh(); refresh();
} }
ScriptManager::~ScriptManager() { detach(); } ScriptManager::~ScriptManager() {}
QStringList ScriptManager::getScriptFileNames(const QDir &dir) const { QStringList ScriptManager::getScriptFileNames(const QDir &dir) const {
if (!dir.exists()) { if (!dir.exists()) {
@ -72,6 +73,11 @@ QString ScriptManager::readJsonObjString(const QJsonObject &jobj,
return {}; return {};
} }
bool ScriptManager::readJsonObjBool(const QJsonObject &jobj,
const QString &key) {
return jobj.value(key).toBool();
}
QMenu *ScriptManager::buildUpScriptDirMenu(QWidget *parent, QMenu *ScriptManager::buildUpScriptDirMenu(QWidget *parent,
const QStringList &files, const QStringList &files,
bool isSys) { bool isSys) {
@ -166,6 +172,7 @@ ScriptManager::ensureDirMeta(const QFileInfo &info) {
jobj.insert(QStringLiteral("license"), QLatin1String()); jobj.insert(QStringLiteral("license"), QLatin1String());
jobj.insert(QStringLiteral("homepage"), QLatin1String()); jobj.insert(QStringLiteral("homepage"), QLatin1String());
jobj.insert(QStringLiteral("comment"), QLatin1String()); jobj.insert(QStringLiteral("comment"), QLatin1String());
jobj.insert(QStringLiteral("hexmenu"), false);
QFile f(base.absoluteFilePath(QStringLiteral(".wingasmeta"))); QFile f(base.absoluteFilePath(QStringLiteral(".wingasmeta")));
if (f.open(QFile::WriteOnly | QFile::Text)) { if (f.open(QFile::WriteOnly | QFile::Text)) {
QJsonDocument jdoc(jobj); QJsonDocument jdoc(jobj);
@ -194,6 +201,8 @@ ScriptManager::ensureDirMeta(const QFileInfo &info) {
readJsonObjString(jobj, QStringLiteral("homepage")); readJsonObjString(jobj, QStringLiteral("homepage"));
meta.comment = meta.comment =
readJsonObjString(jobj, QStringLiteral("comment")); readJsonObjString(jobj, QStringLiteral("comment"));
meta.isContextMenu =
readJsonObjBool(jobj, QStringLiteral("hexmenu"));
} else { } else {
meta.name = info.fileName(); meta.name = info.fileName();
} }
@ -206,14 +215,6 @@ ScriptManager::ensureDirMeta(const QFileInfo &info) {
return meta; return meta;
} }
void ScriptManager::attach(ScriptingConsole *console) {
if (console) {
_console = console;
}
}
void ScriptManager::detach() { _console = nullptr; }
ScriptManager::ScriptDirMeta ScriptManager::ScriptDirMeta
ScriptManager::usrDirMeta(const QString &cat) const { ScriptManager::usrDirMeta(const QString &cat) const {
return _usrDirMetas.value(cat); return _usrDirMetas.value(cat);
@ -224,9 +225,10 @@ ScriptManager::sysDirMeta(const QString &cat) const {
return _sysDirMetas.value(cat); return _sysDirMetas.value(cat);
} }
ScriptManager::ScriptActionMaps QList<QMenu *>
ScriptManager::buildUpRibbonScriptRunner(RibbonButtonGroup *group) { ScriptManager::buildUpScriptRunnerContext(RibbonButtonGroup *group,
ScriptActionMaps maps; QWidget *parent) {
QList<QMenu *> maps;
auto &sm = ScriptManager::instance(); auto &sm = ScriptManager::instance();
auto &stm = SettingManager::instance(); auto &stm = SettingManager::instance();
@ -236,10 +238,20 @@ ScriptManager::buildUpRibbonScriptRunner(RibbonButtonGroup *group) {
if (hideCats.contains(cat)) { if (hideCats.contains(cat)) {
continue; continue;
} }
maps.sysList << addPannelAction(
group, ICONRES(QStringLiteral("scriptfolder")), auto meta = sm.sysDirMeta(cat);
sm.sysDirMeta(cat).name,
addPannelAction(
group, ICONRES(QStringLiteral("scriptfolder")), meta.name,
buildUpScriptDirMenu(group, sm.getSysScriptFileNames(cat), true)); buildUpScriptDirMenu(group, sm.getSysScriptFileNames(cat), true));
if (meta.isContextMenu) {
auto m = buildUpScriptDirMenu(parent, sm.getSysScriptFileNames(cat),
true);
m->setTitle(meta.name);
m->setIcon(ICONRES(QStringLiteral("scriptfolder")));
maps << m;
}
} }
hideCats = stm.usrHideCats(); hideCats = stm.usrHideCats();
@ -247,23 +259,37 @@ ScriptManager::buildUpRibbonScriptRunner(RibbonButtonGroup *group) {
if (hideCats.contains(cat)) { if (hideCats.contains(cat)) {
continue; continue;
} }
maps.usrList << addPannelAction( auto meta = sm.usrDirMeta(cat);
group, ICONRES(QStringLiteral("scriptfolderusr")),
sm.usrDirMeta(cat).name, addPannelAction(
group, ICONRES(QStringLiteral("scriptfolderusr")), meta.name,
buildUpScriptDirMenu(group, sm.getUsrScriptFileNames(cat), false)); buildUpScriptDirMenu(group, sm.getUsrScriptFileNames(cat), false));
if (meta.isContextMenu) {
auto m = buildUpScriptDirMenu(parent, sm.getSysScriptFileNames(cat),
true);
m->setTitle(meta.name);
m->setIcon(ICONRES(QStringLiteral("scriptfolderusr")));
maps << m;
}
} }
return maps; return maps;
} }
void ScriptManager::runScript(const QString &filename) { void ScriptManager::runScript(const QString &filename) {
Q_ASSERT(_console); auto &ins = ScriptMachine::instance();
_console->setMode(ScriptingConsole::Output); if (ins.isRunning(ScriptMachine::Background)) {
_console->stdWarn(tr("Excuting:") + filename); auto ret = QMessageBox::question(nullptr, tr("ScriptRunning"),
_console->newLine(); tr("ScriptRunningRequestLastStop?"));
_console->machine()->executeScript(filename); if (ret == QMessageBox::Yes) {
_console->appendCommandPrompt(); ins.abortScript(ScriptMachine::Background);
_console->setMode(ScriptingConsole::Input); } else {
return;
}
}
ins.executeScript(ScriptMachine::Background, filename);
} }
QStringList ScriptManager::usrScriptsDbCats() const { QStringList ScriptManager::usrScriptsDbCats() const {

View File

@ -24,7 +24,6 @@
#include <QObject> #include <QObject>
#include "QWingRibbon/ribbonbuttongroup.h" #include "QWingRibbon/ribbonbuttongroup.h"
#include "control/scriptingconsole.h"
#include "utilities.h" #include "utilities.h"
class ScriptManager : public QObject { class ScriptManager : public QObject {
@ -38,14 +37,10 @@ public:
QString license; QString license;
QString homepage; QString homepage;
QString comment; QString comment;
bool isContextMenu = false;
bool isSys; // a flag bool isSys; // a flag
}; };
struct ScriptActionMaps {
QList<QToolButton *> sysList;
QList<QToolButton *> usrList;
};
public: public:
static ScriptManager &instance(); static ScriptManager &instance();
@ -65,13 +60,11 @@ public:
void refreshUsrScriptsDbCats(); void refreshUsrScriptsDbCats();
void refreshSysScriptsDbCats(); void refreshSysScriptsDbCats();
void attach(ScriptingConsole *console);
void detach();
ScriptDirMeta usrDirMeta(const QString &cat) const; ScriptDirMeta usrDirMeta(const QString &cat) const;
ScriptDirMeta sysDirMeta(const QString &cat) const; ScriptDirMeta sysDirMeta(const QString &cat) const;
static ScriptActionMaps buildUpRibbonScriptRunner(RibbonButtonGroup *group); static QList<QMenu *> buildUpScriptRunnerContext(RibbonButtonGroup *group,
QWidget *parent);
private: private:
static QToolButton *addPannelAction(RibbonButtonGroup *pannel, static QToolButton *addPannelAction(RibbonButtonGroup *pannel,
@ -122,6 +115,8 @@ private:
QString readJsonObjString(const QJsonObject &jobj, const QString &key); QString readJsonObjString(const QJsonObject &jobj, const QString &key);
bool readJsonObjBool(const QJsonObject &jobj, const QString &key);
static QMenu *buildUpScriptDirMenu(QWidget *parent, static QMenu *buildUpScriptDirMenu(QWidget *parent,
const QStringList &files, bool isSys); const QStringList &files, bool isSys);
@ -133,8 +128,6 @@ private:
QHash<QString, ScriptDirMeta> _usrDirMetas; QHash<QString, ScriptDirMeta> _usrDirMetas;
QHash<QString, ScriptDirMeta> _sysDirMetas; QHash<QString, ScriptDirMeta> _sysDirMetas;
ScriptingConsole *_console = nullptr;
}; };
Q_DECLARE_METATYPE(ScriptManager::ScriptDirMeta) Q_DECLARE_METATYPE(ScriptManager::ScriptDirMeta)

View File

@ -33,12 +33,24 @@
_setUnsavedEditor.setFlag(flag, false); \ _setUnsavedEditor.setFlag(flag, false); \
} }
#define WRITE_CONFIG_EDITOR_RESET(config, flag, dvalue) \
do { \
WRITE_CONFIG(config, dvalue); \
_setUnsavedEditor.setFlag(flag, false); \
} while (0);
#define WRITE_CONFIG_CONSOLE_SET(config, flag, dvalue) \ #define WRITE_CONFIG_CONSOLE_SET(config, flag, dvalue) \
if (this->_setUnsavedConsole.testFlag(flag)) { \ if (this->_setUnsavedConsole.testFlag(flag)) { \
WRITE_CONFIG(config, dvalue); \ WRITE_CONFIG(config, dvalue); \
_setUnsavedConsole.setFlag(flag, false); \ _setUnsavedConsole.setFlag(flag, false); \
} }
#define WRITE_CONFIG_CONSOLE_RESET(config, flag, dvalue) \
do { \
WRITE_CONFIG(config, dvalue); \
_setUnsavedConsole.setFlag(flag, false); \
} while (0);
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_FONT, ("codeedit.font")) Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_FONT, ("codeedit.font"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_FONT_SIZE, ("codeedit.fontsize")) Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_FONT_SIZE, ("codeedit.fontsize"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_THEME, ("codeedit.theme")) Q_GLOBAL_STATIC_WITH_ARGS(QString, CODEEDIT_THEME, ("codeedit.theme"))
@ -200,56 +212,59 @@ void ScriptSettings::save(SETTINGS cat) {
} }
void ScriptSettings::reset(SETTINGS cat) { void ScriptSettings::reset(SETTINGS cat) {
__reset(cat);
load();
}
void ScriptSettings::__reset(SETTINGS cat) {
HANDLE_CONFIG; HANDLE_CONFIG;
if (cat.testFlag(SETTING::EDITOR)) { if (cat.testFlag(SETTING::EDITOR)) {
WRITE_CONFIG_EDITOR_SET(CODEEDIT_FONT, SETTING_ITEM::FONT, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_FONT, SETTING_ITEM::FONT,
_defaultFont.defaultFamily()); _defaultFont.defaultFamily());
WRITE_CONFIG_EDITOR_SET(CODEEDIT_FONT_SIZE, SETTING_ITEM::FONT_SIZE, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_FONT_SIZE, SETTING_ITEM::FONT_SIZE,
10); 10);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_THEME, SETTING_ITEM::THEME, {}); WRITE_CONFIG_EDITOR_RESET(CODEEDIT_THEME, SETTING_ITEM::THEME, {});
WRITE_CONFIG_EDITOR_SET(CODEEDIT_TABS_WIDTH, SETTING_ITEM::TAB_WIDTH, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_TABS_WIDTH, SETTING_ITEM::TAB_WIDTH,
4); 4);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_INDENTATION, SETTING_ITEM::INDENTATION, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_INDENTATION,
0); SETTING_ITEM::INDENTATION, 0);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_MATCH_BRACES, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_MATCH_BRACES,
SETTING_ITEM::MATCH_BRACES, true); SETTING_ITEM::MATCH_BRACES, true);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_WORD_WRAP, SETTING_ITEM::WORD_WRAP, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_WORD_WRAP, SETTING_ITEM::WORD_WRAP,
false); false);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_SHOW_LINENUMBER, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_SHOW_LINENUMBER,
SETTING_ITEM::SHOW_LINENUMBER, true); SETTING_ITEM::SHOW_LINENUMBER, true);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_SHOW_FOLDING, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_SHOW_FOLDING,
SETTING_ITEM::SHOW_FOLDING, true); SETTING_ITEM::SHOW_FOLDING, true);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_SHOW_INDENTGUIDES, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_SHOW_INDENTGUIDES,
SETTING_ITEM::SHOW_INDENTGUIDES, true); SETTING_ITEM::SHOW_INDENTGUIDES, true);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_SHOW_LONGLINEEDGE, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_SHOW_LONGLINEEDGE,
SETTING_ITEM::SHOW_LONGLINEEDGE, false); SETTING_ITEM::SHOW_LONGLINEEDGE, false);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_SHOW_WHITESPACE, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_SHOW_WHITESPACE,
SETTING_ITEM::SHOW_WHITESPACE, false); SETTING_ITEM::SHOW_WHITESPACE, false);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_AUTO_CLOSE_CHAR, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_AUTO_CLOSE_CHAR,
SETTING_ITEM::AUTO_CLOSE_CHAR, true); SETTING_ITEM::AUTO_CLOSE_CHAR, true);
WRITE_CONFIG_EDITOR_SET(CODEEDIT_AUTO_IDEN, SETTING_ITEM::AUTO_IDEN, WRITE_CONFIG_EDITOR_RESET(CODEEDIT_AUTO_IDEN, SETTING_ITEM::AUTO_IDEN,
true); true);
} }
if (cat.testFlag(SETTING::CONSOLE)) { if (cat.testFlag(SETTING::CONSOLE)) {
WRITE_CONFIG_CONSOLE_SET(CONSOLE_FONT, SETTING_ITEM::FONT, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_FONT, SETTING_ITEM::FONT,
_defaultFont.defaultFamily()); _defaultFont.defaultFamily());
WRITE_CONFIG_CONSOLE_SET(CONSOLE_FONT_SIZE, SETTING_ITEM::FONT_SIZE, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_FONT_SIZE, SETTING_ITEM::FONT_SIZE,
10); 10);
WRITE_CONFIG_CONSOLE_SET(CONSOLE_THEME, SETTING_ITEM::THEME, {}); WRITE_CONFIG_CONSOLE_RESET(CONSOLE_THEME, SETTING_ITEM::THEME, {});
WRITE_CONFIG_CONSOLE_SET(CONSOLE_TABS_WIDTH, SETTING_ITEM::TAB_WIDTH, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_TABS_WIDTH, SETTING_ITEM::TAB_WIDTH,
4); 4);
WRITE_CONFIG_CONSOLE_SET(CONSOLE_INDENTATION, SETTING_ITEM::INDENTATION, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_INDENTATION,
0); SETTING_ITEM::INDENTATION, 0);
WRITE_CONFIG_CONSOLE_SET(CONSOLE_MATCH_BRACES, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_MATCH_BRACES,
SETTING_ITEM::MATCH_BRACES, true); SETTING_ITEM::MATCH_BRACES, true);
WRITE_CONFIG_CONSOLE_SET(CONSOLE_SHOW_WHITESPACE, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_SHOW_WHITESPACE,
SETTING_ITEM::SHOW_WHITESPACE, false); SETTING_ITEM::SHOW_WHITESPACE, false);
WRITE_CONFIG_CONSOLE_SET(CONSOLE_AUTO_CLOSE_CHAR, WRITE_CONFIG_CONSOLE_RESET(CONSOLE_AUTO_CLOSE_CHAR,
SETTING_ITEM::AUTO_CLOSE_CHAR, true); SETTING_ITEM::AUTO_CLOSE_CHAR, true);
} }
load();
} }
ScriptSettings::ScriptSettings() : QObject() { ScriptSettings::ScriptSettings() : QObject() {

View File

@ -57,6 +57,8 @@ public:
void save(SETTINGS cat = SETTING::ALL); void save(SETTINGS cat = SETTING::ALL);
void reset(SETTINGS cat = SETTING::ALL); void reset(SETTINGS cat = SETTING::ALL);
void __reset(SETTINGS cat);
public: public:
QString editorFontFamily() const; QString editorFontFamily() const;
void setEditorFontFamily(const QString &newEditorFontFamily); void setEditorFontFamily(const QString &newEditorFontFamily);

View File

@ -31,6 +31,12 @@
_setUnsaved.setFlag(SettingManager::SETTING_ITEM::config, false); \ _setUnsaved.setFlag(SettingManager::SETTING_ITEM::config, false); \
} }
#define WRITE_CONFIG_RESET(config, dvalue) \
do { \
WRITE_CONFIG(config, dvalue); \
_setUnsaved.setFlag(SettingManager::SETTING_ITEM::config, false); \
} while (0);
Q_GLOBAL_STATIC_WITH_ARGS(QString, DOCK_LAYOUT, ("dock.layout")) Q_GLOBAL_STATIC_WITH_ARGS(QString, DOCK_LAYOUT, ("dock.layout"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_DOCK_LAYOUT, ("script.layout")) Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_DOCK_LAYOUT, ("script.layout"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, APP_LASTUSED_PATH, ("app.lastusedpath")) Q_GLOBAL_STATIC_WITH_ARGS(QString, APP_LASTUSED_PATH, ("app.lastusedpath"))
@ -59,6 +65,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_RECENTFILES, ("script.recentfiles"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ALLOW_USRSCRIPT_INROOT, Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ALLOW_USRSCRIPT_INROOT,
("script.allowUsrScriptRoot")) ("script.allowUsrScriptRoot"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ENABLE, ("script.enable")) 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_USRHIDECATS, ("script.usrHideCats"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_SYSHIDECATS, ("script.sysHideCats")) Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_SYSHIDECATS, ("script.sysHideCats"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_USESYS_FILEDIALOG, Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_USESYS_FILEDIALOG,
@ -113,6 +120,7 @@ void SettingManager::load() {
READ_CONFIG_BOOL(m_enablePlgInRoot, PLUGIN_ENABLE_ROOT, false); READ_CONFIG_BOOL(m_enablePlgInRoot, PLUGIN_ENABLE_ROOT, false);
READ_CONFIG_INT_POSITIVE(m_editorfontSize, EDITOR_FONTSIZE, READ_CONFIG_INT_POSITIVE(m_editorfontSize, EDITOR_FONTSIZE,
defaultFontSize); defaultFontSize);
m_editorfontSize = qBound(5, m_editorfontSize, 25);
READ_CONFIG_BOOL(m_editorShowHeader, EDITOR_SHOW_ADDR, true); READ_CONFIG_BOOL(m_editorShowHeader, EDITOR_SHOW_ADDR, true);
READ_CONFIG_BOOL(m_editorShowcol, EDITOR_SHOW_COL, true); READ_CONFIG_BOOL(m_editorShowcol, EDITOR_SHOW_COL, true);
READ_CONFIG_BOOL(m_editorShowtext, EDITOR_SHOW_TEXT, true); READ_CONFIG_BOOL(m_editorShowtext, EDITOR_SHOW_TEXT, true);
@ -146,6 +154,8 @@ void SettingManager::load() {
READ_CONFIG_BOOL(m_scriptEnabled, SCRIPT_ENABLE, true); READ_CONFIG_BOOL(m_scriptEnabled, SCRIPT_ENABLE, true);
READ_CONFIG_BOOL(m_allowUsrScriptInRoot, SCRIPT_ALLOW_USRSCRIPT_INROOT, READ_CONFIG_BOOL(m_allowUsrScriptInRoot, SCRIPT_ALLOW_USRSCRIPT_INROOT,
false); false);
READ_CONFIG_INT(m_scriptTimeout, SCRIPT_TIMEOUT, 10);
m_scriptTimeout = qBound(0, m_scriptTimeout, 312480);
m_usrHideCats = m_usrHideCats =
READ_CONFIG(SCRIPT_USRHIDECATS, QStringList()).toStringList(); READ_CONFIG(SCRIPT_USRHIDECATS, QStringList()).toStringList();
m_sysHideCats = m_sysHideCats =
@ -185,6 +195,16 @@ QVariantList SettingManager::getVarList(
return varlist; 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; } qsizetype SettingManager::logCount() const { return m_logCount; }
void SettingManager::setLogCount(qsizetype newLogCount) { void SettingManager::setLogCount(qsizetype newLogCount) {
@ -392,6 +412,7 @@ void SettingManager::save(SETTINGS cat) {
} }
if (cat.testFlag(SETTING::SCRIPT)) { if (cat.testFlag(SETTING::SCRIPT)) {
WRITE_CONFIG_SET(SCRIPT_ENABLE, m_scriptEnabled); 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_ALLOW_USRSCRIPT_INROOT, m_allowUsrScriptInRoot);
WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, m_usrHideCats); WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, m_usrHideCats);
WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, m_sysHideCats); WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, m_sysHideCats);
@ -409,44 +430,49 @@ void SettingManager::save(SETTINGS cat) {
} }
void SettingManager::reset(SETTINGS cat) { void SettingManager::reset(SETTINGS cat) {
__reset(cat);
load();
}
void SettingManager::__reset(SETTINGS cat) {
HANDLE_CONFIG; HANDLE_CONFIG;
if (cat.testFlag(SETTING::APP)) { if (cat.testFlag(SETTING::APP)) {
WRITE_CONFIG_SET(SKIN_THEME, 0); WRITE_CONFIG_RESET(SKIN_THEME, 0);
WRITE_CONFIG_SET(APP_LANGUAGE, QString()); WRITE_CONFIG_RESET(APP_LANGUAGE, QString());
WRITE_CONFIG_SET(APP_FONTFAMILY, _defaultFont.family()); WRITE_CONFIG_RESET(APP_FONTFAMILY, _defaultFont.family());
WRITE_CONFIG_SET(APP_FONTSIZE, _defaultFont.pointSize()); WRITE_CONFIG_RESET(APP_FONTSIZE, _defaultFont.pointSize());
WRITE_CONFIG_SET(APP_WINDOWSIZE, Qt::WindowMaximized); WRITE_CONFIG_RESET(APP_WINDOWSIZE, Qt::WindowMaximized);
} }
if (cat.testFlag(SETTING::PLUGIN)) { if (cat.testFlag(SETTING::PLUGIN)) {
WRITE_CONFIG_SET(PLUGIN_ENABLE, true); WRITE_CONFIG_RESET(PLUGIN_ENABLE, true);
WRITE_CONFIG_SET(PLUGIN_ENABLE_ROOT, false); WRITE_CONFIG_RESET(PLUGIN_ENABLE_ROOT, false);
} }
if (cat.testFlag(SETTING::EDITOR)) { if (cat.testFlag(SETTING::EDITOR)) {
WRITE_CONFIG_SET(EDITOR_FONTSIZE, _defaultFont.pointSize()); WRITE_CONFIG_RESET(EDITOR_FONTSIZE, _defaultFont.pointSize());
WRITE_CONFIG_SET(EDITOR_SHOW_ADDR, true); WRITE_CONFIG_RESET(EDITOR_SHOW_ADDR, true);
WRITE_CONFIG_SET(EDITOR_SHOW_COL, true); WRITE_CONFIG_RESET(EDITOR_SHOW_COL, true);
WRITE_CONFIG_SET(EDITOR_SHOW_TEXT, true); WRITE_CONFIG_RESET(EDITOR_SHOW_TEXT, true);
WRITE_CONFIG_SET(EDITOR_FIND_MAXCOUNT, 100); WRITE_CONFIG_RESET(EDITOR_FIND_MAXCOUNT, 100);
WRITE_CONFIG_SET(EDITOR_COPY_LIMIT, 100); WRITE_CONFIG_RESET(EDITOR_COPY_LIMIT, 100);
WRITE_CONFIG_SET(EDITOR_DECSTRLIMIT, 10); WRITE_CONFIG_RESET(EDITOR_DECSTRLIMIT, 10);
} }
if (cat.testFlag(SETTING::SCRIPT)) { if (cat.testFlag(SETTING::SCRIPT)) {
WRITE_CONFIG_SET(SCRIPT_ENABLE, true); WRITE_CONFIG_RESET(SCRIPT_ENABLE, true);
WRITE_CONFIG_SET(SCRIPT_ALLOW_USRSCRIPT_INROOT, false); WRITE_CONFIG_RESET(SCRIPT_TIMEOUT, 10);
WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, QStringList()); WRITE_CONFIG_RESET(SCRIPT_ALLOW_USRSCRIPT_INROOT, false);
WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, QStringList()); WRITE_CONFIG_RESET(SCRIPT_USRHIDECATS, QStringList());
WRITE_CONFIG_RESET(SCRIPT_SYSHIDECATS, QStringList());
} }
if (cat.testFlag(SETTING::OTHER)) { if (cat.testFlag(SETTING::OTHER)) {
WRITE_CONFIG_SET(OTHER_USESYS_FILEDIALOG, true); WRITE_CONFIG_RESET(OTHER_USESYS_FILEDIALOG, true);
#ifdef WINGHEX_USE_FRAMELESS #ifdef WINGHEX_USE_FRAMELESS
WRITE_CONFIG_SET(OTHER_USE_NATIVE_TITLEBAR, false); WRITE_CONFIG_RESET(OTHER_USE_NATIVE_TITLEBAR, false);
#endif #endif
WRITE_CONFIG_SET(OTHER_DONT_USE_SPLASH, false); WRITE_CONFIG_RESET(OTHER_DONT_USE_SPLASH, false);
WRITE_CONFIG_SET(OTHER_CHECK_UPDATE, false); WRITE_CONFIG_RESET(OTHER_CHECK_UPDATE, false);
WRITE_CONFIG_SET(OTHER_LOG_LEVEL, Logger::defaultLevel()); WRITE_CONFIG_RESET(OTHER_LOG_LEVEL, Logger::defaultLevel());
WRITE_CONFIG_SET(OTHER_LOG_COUNT, 20); WRITE_CONFIG_RESET(OTHER_LOG_COUNT, 20);
} }
load();
} }
qsizetype SettingManager::decodeStrlimit() const { return m_decodeStrlimit; } qsizetype SettingManager::decodeStrlimit() const { return m_decodeStrlimit; }

View File

@ -59,7 +59,7 @@ private:
EDITOR_SHOW_ADDR = 1u << 11, EDITOR_SHOW_ADDR = 1u << 11,
EDITOR_SHOW_COL = 1u << 12, EDITOR_SHOW_COL = 1u << 12,
EDITOR_SHOW_TEXT = 1u << 13, EDITOR_SHOW_TEXT = 1u << 13,
// EDITOR_ENCODING = 1u << 14, // Reserved SCRIPT_TIMEOUT = 1u << 14,
EDITOR_FIND_MAXCOUNT = 1u << 15, EDITOR_FIND_MAXCOUNT = 1u << 15,
EDITOR_COPY_LIMIT = 1u << 16, EDITOR_COPY_LIMIT = 1u << 16,
EDITOR_DECSTRLIMIT = 1u << 17, EDITOR_DECSTRLIMIT = 1u << 17,
@ -119,6 +119,8 @@ public:
void save(SETTINGS cat = SETTING::ALL); void save(SETTINGS cat = SETTING::ALL);
void reset(SETTINGS cat); void reset(SETTINGS cat);
void __reset(SETTINGS cat);
QList<RecentFileManager::RecentInfo> recentHexFiles() const; QList<RecentFileManager::RecentInfo> recentHexFiles() const;
void void
setRecentFiles(const QList<RecentFileManager::RecentInfo> &newRecentFiles); setRecentFiles(const QList<RecentFileManager::RecentInfo> &newRecentFiles);
@ -172,6 +174,9 @@ public:
qsizetype logCount() const; qsizetype logCount() const;
void setLogCount(qsizetype newLogCount); void setLogCount(qsizetype newLogCount);
int scriptTimeout() const;
void setScriptTimeout(int newScriptTimeout);
public: public:
void checkWriteableAndWarn(); void checkWriteableAndWarn();
@ -229,6 +234,8 @@ private:
int m_logLevel = 0; int m_logLevel = 0;
qsizetype m_logCount = 20; qsizetype m_logCount = 20;
int m_scriptTimeout = 60; // min
private: private:
QFont _defaultFont; QFont _defaultFont;
SETTING_ITEMS _setUnsaved; SETTING_ITEMS _setUnsaved;

File diff suppressed because it is too large Load Diff

View File

@ -23,9 +23,7 @@
#include <QFileDialog> #include <QFileDialog>
#include <any>
#include <functional> #include <functional>
#include <vector>
class asIScriptEngine; class asIScriptEngine;
class ScriptMachine; class ScriptMachine;
@ -73,9 +71,6 @@ public:
void installAPI(ScriptMachine *machine); void installAPI(ScriptMachine *machine);
void installBasicTypes(asIScriptEngine *engine); void installBasicTypes(asIScriptEngine *engine);
void setBindingConsole(ScriptingConsole *console);
void unBindConsole();
static QString qvariantCastASString(const QMetaType::Type &id); static QString qvariantCastASString(const QMetaType::Type &id);
static int qvariantCastASID(asIScriptEngine *engine, static int qvariantCastASID(asIScriptEngine *engine,
@ -100,25 +95,13 @@ private:
void installHexBaseType(asIScriptEngine *engine); void installHexBaseType(asIScriptEngine *engine);
void installHexReaderAPI(asIScriptEngine *engine); void installHexReaderAPI(asIScriptEngine *engine);
void installHexControllerAPI(asIScriptEngine *engine); void installHexControllerAPI(asIScriptEngine *engine);
void installDataVisualAPI(asIScriptEngine *engine);
void installScriptFns(asIScriptEngine *engine); void installScriptFns(asIScriptEngine *engine);
void installScriptUnSafeFns(asIScriptEngine *engine); void installScriptUnSafeFns(asIScriptEngine *engine);
void installScriptEnums(asIScriptEngine *engine); void installScriptEnums(asIScriptEngine *engine);
private: private:
template <class T> void registerAPI(asIScriptEngine *engine, const asSFuncPtr &fn,
void registerAPI(asIScriptEngine *engine, const std::function<T> &fn, const char *sig);
const char *sig) {
_fnbuffer.push_back(fn);
auto r = engine->RegisterGlobalFunction(
sig, asMETHOD(std::function<T>, operator()),
asCALL_THISCALL_ASGLOBAL,
std::any_cast<std::function<T>>(&_fnbuffer.back()));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
}
using WrapperFn = std::function<void(asIScriptGeneric *)>;
private: private:
QStringList cArray2QStringList(const CScriptArray &array, int stringID, QStringList cArray2QStringList(const CScriptArray &array, int stringID,
@ -203,22 +186,9 @@ private:
// ========================================================= // =========================================================
QString getSenderHeader(const WingHex::SenderInfo &sender);
void cleanUpHandles(const QVector<int> &handles); void cleanUpHandles(const QVector<int> &handles);
private: private:
QString _InputBox_getItem(const QString &title, const QString &label,
const CScriptArray &items, int current,
bool editable, bool *ok,
Qt::InputMethodHints inputMethodHints);
CScriptArray *_FileDialog_getOpenFileNames(const QString &caption,
const QString &dir,
const QString &filter,
QString *selectedFilter,
QFileDialog::Options options);
CScriptArray *_HexReader_selectedBytes(qsizetype index); CScriptArray *_HexReader_selectedBytes(qsizetype index);
CScriptArray *_HexReader_selectionBytes(); CScriptArray *_HexReader_selectionBytes();
@ -235,34 +205,92 @@ private:
bool _HexController_appendBytes(const CScriptArray &ba); bool _HexController_appendBytes(const CScriptArray &ba);
private: void _UI_Toast(const QString &message, const QString &icon);
bool _DataVisual_updateTextList(const CScriptArray &data,
const QString &title,
asIScriptFunction *click,
asIScriptFunction *dblclick);
bool _DataVisual_updateTextTree(const QString &json, const QString &title, QColor _Color_get(const QString &caption);
asIScriptFunction *click,
asIScriptFunction *dblclick);
bool _DataVisual_updateTextTable(const QString &json,
const CScriptArray &headers,
const CScriptArray &headerNames,
const QString &title,
asIScriptFunction *click,
asIScriptFunction *dblclick);
private: private:
std::vector<std::any> _fnbuffer; void _MSG_AboutQt(const QString &title);
QMessageBox::StandardButton
_MSG_Information(const QString &title, const QString &text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton);
QMessageBox::StandardButton
_MSG_Question(const QString &title, const QString &text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton);
QMessageBox::StandardButton
_MSG_Warning(const QString &title, const QString &text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton);
QMessageBox::StandardButton
_MSG_Critical(const QString &title, const QString &text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton);
void _MSG_About(const QString &title, const QString &text);
QMessageBox::StandardButton
_MSG_msgbox(QMessageBox::Icon icon, const QString &title,
const QString &text, QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton);
private:
QString _InputBox_GetText(const QString &title, const QString &label,
QLineEdit::EchoMode echo, const QString &text,
bool *ok, Qt::InputMethodHints inputMethodHints);
QString _InputBox_GetMultiLineText(const QString &title,
const QString &label,
const QString &text, bool *ok,
Qt::InputMethodHints inputMethodHints);
QString _InputBox_getItem(const QString &title, const QString &label,
const CScriptArray &items, int current,
bool editable, bool *ok,
Qt::InputMethodHints inputMethodHints);
int _InputBox_GetInt(const QString &title, const QString &label, int value,
int minValue, int maxValue, int step, bool *ok);
double _InputBox_GetDouble(const QString &title, const QString &label,
double value, double minValue, double maxValue,
int decimals, bool *ok, double step);
private:
QString _FileDialog_GetExistingDirectory(const QString &caption,
const QString &dir,
QFileDialog::Options options);
QString _FileDialog_GetOpenFileName(const QString &caption,
const QString &dir,
const QString &filter,
QString *selectedFilter,
QFileDialog::Options options);
CScriptArray *_FileDialog_getOpenFileNames(const QString &caption,
const QString &dir,
const QString &filter,
QString *selectedFilter,
QFileDialog::Options options);
QString _FileDialog_GetSaveFileName(const QString &caption,
const QString &dir,
const QString &filter,
QString *selectedFilter,
QFileDialog::Options options);
private:
QVector<IWingPlugin::ScriptFnInfo> _sfns; QVector<IWingPlugin::ScriptFnInfo> _sfns;
QHash<QString, QHash<QString, qsizetype>> _rfns; QHash<QString, QHash<QString, qsizetype>> _rfns;
QVector<IWingPlugin::UNSAFE_SCFNPTR> _usfns; QVector<IWingPlugin::UNSAFE_SCFNPTR> _usfns;
QHash<QString, QHash<QString, qsizetype>> _urfns; QHash<QString, QHash<QString, qsizetype>> _urfns;
ScriptingConsole *_console = nullptr;
QHash<QString, QHash<QString, QList<QPair<QString, int>>>> _objs; QHash<QString, QHash<QString, QList<QPair<QString, int>>>> _objs;
QVector<int> _handles; QVector<int> _handles;

View File

@ -1,6 +1,8 @@
#include "wingconsolehighligher.h" #include "wingconsolehighligher.h"
#include <KSyntaxHighlighting/FoldingRegion> #include <KSyntaxHighlighting/FoldingRegion>
#include <KSyntaxHighlighting/Format>
#include <KSyntaxHighlighting/Theme>
WingConsoleHighligher::WingConsoleHighligher(QTextDocument *document) WingConsoleHighligher::WingConsoleHighligher(QTextDocument *document)
: WingSyntaxHighlighter(document) {} : WingSyntaxHighlighter(document) {}
@ -18,11 +20,15 @@ void WingConsoleHighligher::applyFormat(
auto off = offsetv.toInt(&b); auto off = offsetv.toInt(&b);
if (b) { if (b) {
if (off < 0) { if (off < 0) {
// don't highlight if (off == -2) {
return; WingSyntaxHighlighter::applyFormat(
offset, length, KSyntaxHighlighting::Format());
}
} else { } else {
if (offset <= off) { if (offset <= off) {
auto div = off - offset; auto div = off - offset;
WingSyntaxHighlighter::applyFormat(
offset, div, KSyntaxHighlighting::Format());
auto rest = length - div; auto rest = length - div;
if (rest <= 0) { if (rest <= 0) {
return; return;

View File

@ -95,7 +95,7 @@ WingCStruct::WingCStruct() : WingHex::IWingPlugin() {
info.fn = std::bind( info.fn = std::bind(
QOverload<const QVariantList &>::of(&WingCStruct::structTypes), QOverload<const QVariantList &>::of(&WingCStruct::structTypes),
this, std::placeholders::_1); this, std::placeholders::_1);
info.ret = MetaType(MetaType::String | MetaType::Array); info.ret = MetaType::String | MetaType::Array;
_scriptInfo.insert(QStringLiteral("structTypes"), info); _scriptInfo.insert(QStringLiteral("structTypes"), info);
} }
@ -125,7 +125,7 @@ WingCStruct::WingCStruct() : WingHex::IWingPlugin() {
info.fn = std::bind( info.fn = std::bind(
QOverload<const QVariantList &>::of(&WingCStruct::constDefines), QOverload<const QVariantList &>::of(&WingCStruct::constDefines),
this, std::placeholders::_1); this, std::placeholders::_1);
info.ret = MetaType(MetaType::String | MetaType::Array); info.ret = MetaType::String | MetaType::Array;
_scriptInfo.insert(QStringLiteral("constDefines"), info); _scriptInfo.insert(QStringLiteral("constDefines"), info);
} }
@ -166,7 +166,7 @@ WingCStruct::WingCStruct() : WingHex::IWingPlugin() {
info.fn = std::bind( info.fn = std::bind(
QOverload<const QVariantList &>::of(&WingCStruct::readRaw), this, QOverload<const QVariantList &>::of(&WingCStruct::readRaw), this,
std::placeholders::_1); std::placeholders::_1);
info.ret = MetaType(MetaType::Byte | MetaType::Array); info.ret = MetaType::Byte | MetaType::Array;
info.params.append( info.params.append(
qMakePair(getqsizetypeMetaType(), QStringLiteral("offset"))); qMakePair(getqsizetypeMetaType(), QStringLiteral("offset")));
@ -542,7 +542,6 @@ CScriptDictionary *WingCStruct::convert2AsDictionary(const QVariantHash &hash) {
switch (type) { switch (type) {
case QMetaType::Bool: case QMetaType::Bool:
case QMetaType::UChar: case QMetaType::UChar:
case QMetaType::Char:
case QMetaType::Int: case QMetaType::Int:
case QMetaType::Long: case QMetaType::Long:
case QMetaType::LongLong: case QMetaType::LongLong:
@ -564,6 +563,13 @@ CScriptDictionary *WingCStruct::convert2AsDictionary(const QVariantHash &hash) {
case QMetaType::Float: case QMetaType::Float:
dic->Set(p->first, var.toDouble()); dic->Set(p->first, var.toDouble());
break; break;
case QMetaType::Char: {
auto v = var.value<char>();
auto ch = new QChar(v);
auto id = engine->GetTypeIdByDecl("char");
dic->Set(p->first, ch, id);
break;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
case QMetaType::Char16: { case QMetaType::Char16: {
auto v = var.value<char16_t>(); auto v = var.value<char16_t>();

View File

@ -21,6 +21,7 @@
#include "utilities.h" #include "utilities.h"
#include <QApplication> #include <QApplication>
#include <QPushButton>
#include <QResizeEvent> #include <QResizeEvent>
WingMessageBox::WingMessageBox() {} WingMessageBox::WingMessageBox() {}
@ -161,5 +162,10 @@ WingMessageBox::msgbox(QWidget *parent, QMessageBox::Icon icon,
QObject::connect(msgbox, &QMessageBox::finished, &d, QObject::connect(msgbox, &QMessageBox::finished, &d,
&FramelessDialogBase::done); &FramelessDialogBase::done);
return static_cast<QMessageBox::StandardButton>(d.exec()); auto ret = d.exec();
if (ret == 0) {
return msgbox->standardButton(msgbox->defaultButton());
}
return static_cast<QMessageBox::StandardButton>(ret);
} }

View File

@ -13,5 +13,4 @@ The following components are all third-party components used by the software. Th
* [cpptrace](https://github.com/jeremy-rifkin/cpptrace) (MIT) * [cpptrace](https://github.com/jeremy-rifkin/cpptrace) (MIT)
* [QConsoleWidget](https://github.com/gapost/qconsolewidget) (MIT, **FORK** -> AGPL-3.0) * [QConsoleWidget](https://github.com/gapost/qconsolewidget) (MIT, **FORK** -> AGPL-3.0)
* [QColorPicker](https://github.com/arsdever/qcolorpicker) (MIT) * [QColorPicker](https://github.com/arsdever/qcolorpicker) (MIT)
* [QtJsonModel](https://github.com/dridk/QJsonmodel) (MIT)
* [Qt](https://www.qt.io/) (LGPL) * [Qt](https://www.qt.io/) (LGPL)

View File

@ -104,11 +104,20 @@ void CodeEdit::onCompletion(const QModelIndex &index) {
if (selfdata.type == CodeInfoTip::Type::Function || if (selfdata.type == CodeInfoTip::Type::Function ||
selfdata.type == CodeInfoTip::Type::ClsFunction) { selfdata.type == CodeInfoTip::Type::ClsFunction) {
auto args = selfdata.addinfo.value(CodeInfoTip::Args); auto args = selfdata.addinfo.value(CodeInfoTip::Args);
auto cursor = textCursor();
cursor.insertText(QStringLiteral("()")); auto cur = textCursor();
if (!args.isEmpty()) { cur.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::Left); auto ch = cur.selectedText();
setTextCursor(cursor); if (ch.isEmpty() || ch.front().isSpace()) {
auto cursor = textCursor();
cursor.insertText(QStringLiteral("()"));
if (!args.isEmpty()) {
cursor.movePosition(QTextCursor::Left);
setTextCursor(cursor);
}
} else {
auto cursor = textCursor();
cursor.insertText(QStringLiteral("("));
} }
} }
} }
@ -180,6 +189,8 @@ void CodeEdit::applyEditorSetStyle() {
SearchReplaceWidget *CodeEdit::searchWidget() const { return m_searchWidget; } SearchReplaceWidget *CodeEdit::searchWidget() const { return m_searchWidget; }
void CodeEdit::setContentModified(bool b) { emit contentModified(b); }
void CodeEdit::resizeEvent(QResizeEvent *event) { void CodeEdit::resizeEvent(QResizeEvent *event) {
if (event) if (event)
WingCodeEdit::resizeEvent(event); WingCodeEdit::resizeEvent(event);

View File

@ -35,6 +35,9 @@ public:
SearchReplaceWidget *searchWidget() const; SearchReplaceWidget *searchWidget() const;
public:
void setContentModified(bool b);
signals: signals:
void contentModified(bool b); void contentModified(bool b);

View File

@ -36,7 +36,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
constexpr qsizetype FILE_MAX_BUFFER = 0x6400000; // 100MB constexpr qsizetype FILE_MAX_BUFFER = 0x32000000; // 800MB
constexpr auto CLONE_LIMIT = 3; constexpr auto CLONE_LIMIT = 3;
constexpr auto VIEW_PROPERTY = "__VIEW__"; constexpr auto VIEW_PROPERTY = "__VIEW__";
@ -121,6 +121,9 @@ EditorView::EditorView(QWidget *parent)
m_metadata->setDocument(doc); m_metadata->setDocument(doc);
}); });
connect(&_watcher, &QFileSystemWatcher::fileChanged, this,
&EditorView::need2Reload);
applySettings(); applySettings();
// build up call tables // build up call tables
@ -224,7 +227,7 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) {
end = cur->selectionEnd(0).offset(); end = cur->selectionEnd(0).offset();
} break; } break;
default: { default: {
begin = -1; begin = 0;
end = -1; end = -1;
} break; } break;
} }
@ -239,8 +242,12 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) {
contextLen = raw.length(); contextLen = raw.length();
m_findResults->setEncoding(result.encoding); m_findResults->setEncoding(result.encoding);
d->findAllBytes(begin, end, raw, results); d->findAllBytes(begin, end, raw, results);
m_findResults->lastFindData() = qMakePair(data, contextLen);
} else { } else {
contextLen = d->findAllBytesExt(begin, end, result.str, results); // assuming the find pattern is 'xx xx xx xx'
contextLen = std::count(data.begin(), data.end(), ' ') + 1;
d->findAllBytesExt(begin, end, result.str, results);
m_findResults->lastFindData() = qMakePair(data, contextLen);
} }
m_findResults->beginUpdate(); m_findResults->beginUpdate();
@ -254,12 +261,9 @@ EditorView::FindError EditorView::find(const FindDialog::Result &result) {
r.col = r.offset % lineWidth; r.col = r.offset % lineWidth;
m_findResults->results().append(r); m_findResults->results().append(r);
m_findResults->findData().append( m_findResults->findData().append(
readContextFinding(ritem, contextLen, FIND_CONTEXT_SIZE, readContextFinding(ritem, contextLen));
FIND_MAX_DISPLAY_FIND_CHARS));
} }
m_findResults->lastFindData() = data;
m_findResults->endUpdate(); m_findResults->endUpdate();
if (m_findResults->size() >= QHEXVIEW_FIND_LIMIT) { if (m_findResults->size() >= QHEXVIEW_FIND_LIMIT) {
@ -284,6 +288,8 @@ ErrFile EditorView::newFile(size_t index) {
if (isCloneFile()) { if (isCloneFile()) {
return ErrFile::ClonedFile; return ErrFile::ClonedFile;
} }
removeMonitorPaths();
auto istr = QString::number(index); auto istr = QString::number(index);
m_fileName = tr("Untitled") + istr; m_fileName = tr("Untitled") + istr;
this->setWindowTitle(m_fileName); this->setWindowTitle(m_fileName);
@ -320,6 +326,8 @@ ErrFile EditorView::openFile(const QString &filename) {
return ErrFile::Permission; return ErrFile::Permission;
} }
removeMonitorPaths();
m_hex->setDocument(QSharedPointer<QHexDocument>(p)); m_hex->setDocument(QSharedPointer<QHexDocument>(p));
m_hex->setLockedFile(readonly); m_hex->setLockedFile(readonly);
m_hex->setKeepSize(true); m_hex->setKeepSize(true);
@ -335,6 +343,8 @@ ErrFile EditorView::openFile(const QString &filename) {
auto tab = this->tabWidget(); auto tab = this->tabWidget();
tab->setIcon(Utilities::getIconFromFile(style(), m_fileName)); tab->setIcon(Utilities::getIconFromFile(style(), m_fileName));
tab->setToolTip(m_fileName); tab->setToolTip(m_fileName);
addMonitorPath();
} }
return ErrFile::Success; return ErrFile::Success;
@ -372,6 +382,8 @@ ErrFile EditorView::openExtFile(const QString &ext, const QString &file) {
return ErrFile::Error; return ErrFile::Error;
} }
removeMonitorPaths();
m_hex->setDocument(QSharedPointer<QHexDocument>(p)); m_hex->setDocument(QSharedPointer<QHexDocument>(p));
m_hex->setLockedFile(readonly); m_hex->setLockedFile(readonly);
m_hex->setKeepSize(true); m_hex->setKeepSize(true);
@ -558,6 +570,8 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
return ErrFile::Permission; return ErrFile::Permission;
} }
removeMonitorPaths();
if (doc->saveTo(&file, !isExport)) { if (doc->saveTo(&file, !isExport)) {
file.close(); file.close();
@ -567,6 +581,9 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
m_docType = DocumentType::File; m_docType = DocumentType::File;
doc->setDocSaved(); doc->setDocSaved();
} }
addMonitorPath();
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
adjustPermission(); adjustPermission();
#endif #endif
@ -717,6 +734,16 @@ void EditorView::connectDocSavedFlag(EditorView *editor) {
}); });
} }
void EditorView::removeMonitorPaths() {
auto files = _watcher.files();
if (files.isEmpty()) {
return;
}
_watcher.removePaths(files);
}
void EditorView::addMonitorPath() { _watcher.addPath(m_fileName); }
BookMarksModel *EditorView::bookmarksModel() const { return m_bookmarks; } BookMarksModel *EditorView::bookmarksModel() const { return m_bookmarks; }
MetaDataModel *EditorView::metadataModel() const { return m_metadata; } MetaDataModel *EditorView::metadataModel() const { return m_metadata; }
@ -784,34 +811,50 @@ bool EditorView::checkHasUnsavedState() const {
} }
FindResultModel::FindInfo EditorView::readContextFinding(qsizetype offset, FindResultModel::FindInfo EditorView::readContextFinding(qsizetype offset,
qsizetype findSize, qsizetype findSize) {
int contextSize, constexpr long DISPLAY_SIZE = 16;
int maxDisplayBytes) { constexpr long FIND_CONTENXT_LEN = 10;
constexpr long HT_SIZE = (DISPLAY_SIZE - FIND_CONTENXT_LEN) / 2;
auto doc = m_hex->document(); auto doc = m_hex->document();
if (findSize <= FIND_CONTENXT_LEN) {
long leftsize = FIND_CONTENXT_LEN - findSize;
auto rs = std::div(leftsize, 2l);
qsizetype halfSize = maxDisplayBytes / 2; auto headerlen = HT_SIZE + rs.quot + rs.rem;
auto header = doc->read(offset, qMin(findSize, halfSize)); auto taillen = HT_SIZE + rs.quot;
QByteArray tailer;
if (header.size() < findSize) { auto begin = qMax(offset - headerlen, 0);
auto len = qMin(findSize, qsizetype(maxDisplayBytes) - halfSize); auto end = qMin(offset + findSize + taillen, doc->length());
tailer = doc->read(offset + findSize - len, len); auto boff = offset - begin;
auto buffer = doc->read(begin, end - begin + 1);
FindResultModel::FindInfo info;
info.cheader = buffer.left(boff);
info.hbuffer = buffer.sliced(boff, findSize);
info.tbuffer = {};
info.ctailer = buffer.sliced(boff + findSize);
return info;
} else {
constexpr long FIND_CONTENXT_HALF = FIND_CONTENXT_LEN / 2;
auto hbegin = qMax(offset - HT_SIZE, 0);
auto hlen = offset - hbegin + FIND_CONTENXT_HALF;
auto header = doc->read(hbegin, hlen);
auto toff = offset - hbegin;
auto tbegin = offset + findSize - FIND_CONTENXT_HALF;
auto tlen = HT_SIZE + FIND_CONTENXT_HALF;
auto tailer = doc->read(tbegin, tlen);
FindResultModel::FindInfo info;
info.cheader = header.left(toff);
info.hbuffer = header.sliced(toff);
info.tbuffer = tailer.left(FIND_CONTENXT_HALF);
info.ctailer = tailer.sliced(FIND_CONTENXT_HALF);
return info;
} }
auto left = qsizetype(maxDisplayBytes) - header.size() - tailer.size();
// append to contextSize
contextSize += (left / 2);
auto cheader = doc->read(offset - contextSize, contextSize);
auto ctailer = doc->read(offset + findSize, contextSize);
FindResultModel::FindInfo info;
info.cheader = cheader;
info.hbuffer = header;
info.tbuffer = tailer;
info.ctailer = ctailer;
return info;
} }
void EditorView::applyFunctionTables(WingEditorViewWidget *view, void EditorView::applyFunctionTables(WingEditorViewWidget *view,
@ -2033,6 +2076,19 @@ EditorView *EditorView::clone() {
this->m_cloneChildren[this->m_cloneChildren.indexOf(ev)] = nullptr; this->m_cloneChildren[this->m_cloneChildren.indexOf(ev)] = nullptr;
}); });
connect(ev, &EditorView::sigOnCutFile, this, &EditorView::sigOnCutFile);
connect(ev, &EditorView::sigOnCutHex, this, &EditorView::sigOnCutHex);
connect(ev, &EditorView::sigOnCopyFile, this, &EditorView::sigOnCopyFile);
connect(ev, &EditorView::sigOnCopyHex, this, &EditorView::sigOnCopyHex);
connect(ev, &EditorView::sigOnPasteFile, this, &EditorView::sigOnPasteFile);
connect(ev, &EditorView::sigOnPasteHex, this, &EditorView::sigOnPasteHex);
connect(ev, &EditorView::sigOnDelete, this, &EditorView::sigOnDelete);
connect(ev, &EditorView::sigOnFindFile, this, &EditorView::sigOnFindFile);
connect(ev, &EditorView::sigOnGoToLine, this, &EditorView::sigOnGoToLine);
connect(ev, &EditorView::sigOnFill, this, &EditorView::sigOnFill);
connect(ev, &EditorView::sigOnMetadata, this, &EditorView::sigOnMetadata);
connect(ev, &EditorView::sigOnBookMark, this, &EditorView::sigOnBookMark);
auto doc = this->m_hex->document(); auto doc = this->m_hex->document();
ev->m_cloneParent = this; ev->m_cloneParent = this;

View File

@ -18,6 +18,7 @@
#ifndef EDITORVIEW_H #ifndef EDITORVIEW_H
#define EDITORVIEW_H #define EDITORVIEW_H
#include <QFileSystemWatcher>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QStackedWidget> #include <QStackedWidget>
@ -224,9 +225,7 @@ private:
bool checkHasUnsavedState() const; bool checkHasUnsavedState() const;
FindResultModel::FindInfo readContextFinding(qsizetype offset, FindResultModel::FindInfo readContextFinding(qsizetype offset,
qsizetype findSize, qsizetype findSize);
int contextSize,
int maxDisplayBytes);
void applyFunctionTables(WingHex::WingEditorViewWidget *view, void applyFunctionTables(WingHex::WingEditorViewWidget *view,
const CallTable &fns); const CallTable &fns);
@ -537,11 +536,12 @@ private:
parent->addAction(a); parent->addAction(a);
} }
private:
void connectDocSavedFlag(EditorView *editor); void connectDocSavedFlag(EditorView *editor);
void removeMonitorPaths();
void addMonitorPath();
signals: signals:
void sigFileSaved(QString filename, QString oldFileName);
void sigOnCutFile(); void sigOnCutFile();
void sigOnCutHex(); void sigOnCutHex();
void sigOnCopyFile(); void sigOnCopyFile();
@ -555,6 +555,8 @@ signals:
void sigOnMetadata(); void sigOnMetadata();
void sigOnBookMark(); void sigOnBookMark();
void need2Reload();
protected: protected:
bool eventFilter(QObject *watched, QEvent *event) override; bool eventFilter(QObject *watched, QEvent *event) override;
@ -591,6 +593,7 @@ private:
QReadWriteLock _rwlock; QReadWriteLock _rwlock;
CallTable _viewFns; CallTable _viewFns;
QFileSystemWatcher _watcher;
}; };
#endif // EDITORVIEW_H #endif // EDITORVIEW_H

View File

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

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

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

View File

@ -102,3 +102,17 @@ bool QHexTextEdit::isHexMode() const { return m_isHexMode; }
void QHexTextEdit::setIsHexMode(bool newIsHexMode) { void QHexTextEdit::setIsHexMode(bool newIsHexMode) {
m_isHexMode = newIsHexMode; m_isHexMode = newIsHexMode;
} }
void QHexTextEdit::setFindText(const QString &text) {
mText = text;
mText = mText
.removeIf([](const QChar &ch) {
return !std::isalnum(ch.unicode()) && ch != '?';
})
.toUpper();
setText(text);
auto cur = this->textCursor();
cur.movePosition(QTextCursor::End);
setTextCursor(cur);
mCurserPositionPre = cur.position();
}

View File

@ -28,6 +28,10 @@ public:
bool isHexMode() const; bool isHexMode() const;
void setIsHexMode(bool newIsHexMode); void setIsHexMode(bool newIsHexMode);
public:
// must be 'xx xx xx' style
void setFindText(const QString &text);
protected: protected:
void keyPressEvent(QKeyEvent *event) override; void keyPressEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;

View File

@ -1,257 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "qtlonglongspinbox.h"
#include <QEvent>
#include <QKeyEvent>
#include <QLineEdit>
#include <limits>
QtLongLongSpinBox::QtLongLongSpinBox(QWidget *parent)
: QAbstractSpinBox(parent) {
m_minimum = std::numeric_limits<qlonglong>::min();
m_maximum = std::numeric_limits<qlonglong>::max();
m_value = 0;
m_singleStep = 1;
m_base = 10;
setValue(m_value);
}
qlonglong QtLongLongSpinBox::value() const { return m_value; }
void QtLongLongSpinBox::setValue(qlonglong expectedNewValue) {
const qlonglong newValue = qBound(m_minimum, expectedNewValue, m_maximum);
const QString newValueString = QString::number(newValue, m_base);
lineEdit()->setText(m_prefix + newValueString + m_suffix);
if (m_value != newValue) {
m_value = newValue;
emit valueChanged(newValue);
}
}
QString QtLongLongSpinBox::prefix() const { return m_prefix; }
void QtLongLongSpinBox::setPrefix(const QString &prefix) {
m_prefix = prefix;
setValue(m_value);
}
QString QtLongLongSpinBox::suffix() const { return m_suffix; }
void QtLongLongSpinBox::setSuffix(const QString &suffix) {
m_suffix = suffix;
setValue(m_value);
}
QString QtLongLongSpinBox::cleanText() const {
return QString::number(m_value);
}
qlonglong QtLongLongSpinBox::singleStep() const { return m_singleStep; }
void QtLongLongSpinBox::setSingleStep(qlonglong step) { m_singleStep = step; }
qlonglong QtLongLongSpinBox::minimum() const { return m_minimum; }
void QtLongLongSpinBox::setMinimum(qlonglong min) {
m_minimum = min;
if (m_maximum < m_minimum) {
m_maximum = m_minimum;
}
setValue(m_value);
}
qlonglong QtLongLongSpinBox::maximum() const { return m_maximum; }
void QtLongLongSpinBox::setMaximum(qlonglong max) {
m_maximum = max;
if (m_maximum < m_minimum) {
m_maximum = m_minimum;
}
setValue(m_value);
}
void QtLongLongSpinBox::setRange(qlonglong min, qlonglong max) {
if (min < max) {
m_minimum = min;
m_maximum = max;
} else {
m_minimum = max;
m_maximum = min;
}
setValue(m_value);
}
void QtLongLongSpinBox::setDisplayIntegerBase(int base) {
if (m_base != base) {
m_base = base;
setValue(m_value);
}
}
int QtLongLongSpinBox::displayIntegerBase() const { return m_base; }
void QtLongLongSpinBox::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
selectCleanText();
lineEditEditingFinalize();
}
QAbstractSpinBox::keyPressEvent(event);
}
void QtLongLongSpinBox::focusOutEvent(QFocusEvent *event) {
lineEditEditingFinalize();
QAbstractSpinBox::focusOutEvent(event);
}
QAbstractSpinBox::StepEnabled QtLongLongSpinBox::stepEnabled() const {
if (isReadOnly()) {
return StepNone;
}
StepEnabled se = StepNone;
if (wrapping() || m_value < m_maximum) {
se |= StepUpEnabled;
}
if (wrapping() || m_value > m_minimum) {
se |= StepDownEnabled;
}
return se;
}
void QtLongLongSpinBox::stepBy(int steps) {
if (isReadOnly()) {
return;
}
if (m_prefix + QString::number(m_value) + m_suffix != lineEdit()->text()) {
lineEditEditingFinalize();
}
qlonglong newValue = m_value + (steps * m_singleStep);
if (wrapping()) {
// emulating the behavior of QSpinBox
if (newValue > m_maximum) {
if (m_value == m_maximum) {
newValue = m_minimum;
} else {
newValue = m_maximum;
}
} else if (newValue < m_minimum) {
if (m_value == m_minimum) {
newValue = m_maximum;
} else {
newValue = m_minimum;
}
}
} else {
newValue = qBound(m_minimum, newValue, m_maximum);
}
setValue(newValue);
selectCleanText();
}
QValidator::State QtLongLongSpinBox::validate(QString &input, int &pos) const {
// first, we try to interpret as a number without prefixes
bool ok;
const qlonglong value = input.toLongLong(&ok);
if (input.isEmpty() || (ok && value <= m_maximum)) {
input = m_prefix + input + m_suffix;
pos += m_prefix.length();
return QValidator::Acceptable;
}
// if string of text editor aren't simple number, try to interpret it
// as a number with prefix and suffix
bool valid = true;
if (!m_prefix.isEmpty() && !input.startsWith(m_prefix)) {
valid = false;
}
if (!m_suffix.isEmpty() && !input.endsWith(m_suffix)) {
valid = false;
}
if (valid) {
const int start = m_prefix.length();
const int length = input.length() - start - m_suffix.length();
bool ok;
const QString number = input.mid(start, length);
const qlonglong value = number.toLongLong(&ok);
if (number.isEmpty() || (ok && value <= m_maximum)) {
return QValidator::Acceptable;
}
}
// otherwise not acceptable
return QValidator::Invalid;
}
void QtLongLongSpinBox::lineEditEditingFinalize() {
const QString text = lineEdit()->text();
// first, we try to read as a number without prefixes
bool ok;
qlonglong value = text.toLongLong(&ok);
if (ok) {
setValue(value);
return;
}
// if string of text editor aren't simple number, try to interpret it
// as a number with prefix and suffix
bool valid = true;
if (!m_prefix.isEmpty() && !text.startsWith(m_prefix)) {
valid = false;
} else if (!m_suffix.isEmpty() && !text.endsWith(m_suffix)) {
valid = false;
}
if (valid) {
const int start = m_prefix.length();
const int length = text.length() - start - m_suffix.length();
bool ok;
const qlonglong value = text.mid(start, length).toLongLong(&ok);
if (ok) {
setValue(value);
return;
}
}
// otherwise set old value
setValue(m_value);
}
void QtLongLongSpinBox::selectCleanText() {
lineEdit()->setSelection(m_prefix.length(), lineEdit()->text().length() -
m_prefix.length() -
m_suffix.length());
}

View File

@ -1,85 +0,0 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef QTLONGLONGSPINBOX_H
#define QTLONGLONGSPINBOX_H
#include <QAbstractSpinBox>
#include <QtGlobal>
class QtLongLongSpinBox : public QAbstractSpinBox {
Q_OBJECT
public:
explicit QtLongLongSpinBox(QWidget *parent = 0);
qlonglong value() const;
QString prefix() const;
void setPrefix(const QString &prefix);
QString suffix() const;
void setSuffix(const QString &suffix);
QString cleanText() const;
qlonglong singleStep() const;
void setSingleStep(qlonglong val);
qlonglong minimum() const;
void setMinimum(qlonglong min);
qlonglong maximum() const;
void setMaximum(qlonglong max);
void setRange(qlonglong min, qlonglong max);
void setDisplayIntegerBase(int base);
int displayIntegerBase() const;
public slots:
void setValue(qlonglong value);
signals:
void valueChanged(qlonglong i);
protected:
virtual void keyPressEvent(QKeyEvent *event);
virtual void focusOutEvent(QFocusEvent *event);
virtual void stepBy(int steps);
virtual StepEnabled stepEnabled() const;
virtual QValidator::State validate(QString &input, int &pos) const;
private:
void lineEditEditingFinalize();
void selectCleanText();
private:
QString m_prefix;
QString m_suffix;
qlonglong m_singleStep;
qlonglong m_minimum;
qlonglong m_maximum;
qlonglong m_value;
int m_base;
private:
Q_DISABLE_COPY(QtLongLongSpinBox)
};
#endif // QTLONGLONGSPINBOX_H

View File

@ -35,7 +35,7 @@
#include "class/ascompletion.h" #include "class/ascompletion.h"
#include "class/clangformatmanager.h" #include "class/clangformatmanager.h"
ScriptEditor::ScriptEditor(asIScriptEngine *engine, QWidget *parent) ScriptEditor::ScriptEditor(QWidget *parent)
: ads::CDockWidget(nullptr, QString(), parent) { : ads::CDockWidget(nullptr, QString(), parent) {
this->setFeatures( this->setFeatures(
CDockWidget::DockWidgetFocusable | CDockWidget::DockWidgetMovable | CDockWidget::DockWidgetFocusable | CDockWidget::DockWidgetMovable |
@ -48,7 +48,7 @@ ScriptEditor::ScriptEditor(asIScriptEngine *engine, QWidget *parent)
m_editor->setSyntax( m_editor->setSyntax(
m_editor->syntaxRepo().definitionForName("AngelScript")); m_editor->syntaxRepo().definitionForName("AngelScript"));
auto cm = new AsCompletion(engine, m_editor); auto cm = new AsCompletion(m_editor);
connect(cm, &AsCompletion::onFunctionTip, this, connect(cm, &AsCompletion::onFunctionTip, this,
&ScriptEditor::onFunctionTip); &ScriptEditor::onFunctionTip);
@ -57,6 +57,9 @@ ScriptEditor::ScriptEditor(asIScriptEngine *engine, QWidget *parent)
connect(m_editor, &CodeEdit::contentModified, this, connect(m_editor, &CodeEdit::contentModified, this,
[this]() { processTitle(); }); [this]() { processTitle(); });
connect(&_watcher, &QFileSystemWatcher::fileChanged, this,
&ScriptEditor::need2Reload);
this->setWidget(m_editor); this->setWidget(m_editor);
} }
@ -75,12 +78,30 @@ bool ScriptEditor::openFile(const QString &filename) {
} }
m_editor->setPlainText(QString::fromUtf8(f.readAll())); m_editor->setPlainText(QString::fromUtf8(f.readAll()));
f.close(); f.close();
if (!m_fileName.isEmpty()) {
_watcher.removePath(m_fileName);
}
m_fileName = filename; m_fileName = filename;
_watcher.addPath(m_fileName);
processTitle(); processTitle();
return true; return true;
} }
bool ScriptEditor::save(const QString &path) { bool ScriptEditor::save(const QString &path) {
if (!m_fileName.isEmpty()) {
_watcher.removePath(m_fileName);
}
QScopeGuard guard([this, path]() {
if (path.isEmpty()) {
_watcher.addPath(m_fileName);
} else {
_watcher.addPath(path);
}
});
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
auto needAdjustFile = !QFile::exists(path); auto needAdjustFile = !QFile::exists(path);
#endif #endif

View File

@ -21,13 +21,15 @@
#include "Qt-Advanced-Docking-System/src/DockWidget.h" #include "Qt-Advanced-Docking-System/src/DockWidget.h"
#include "control/codeedit.h" #include "control/codeedit.h"
#include <QFileSystemWatcher>
class asIScriptEngine; class asIScriptEngine;
class ScriptEditor : public ads::CDockWidget { class ScriptEditor : public ads::CDockWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit ScriptEditor(asIScriptEngine *engine, QWidget *parent = nullptr); explicit ScriptEditor(QWidget *parent = nullptr);
virtual ~ScriptEditor(); virtual ~ScriptEditor();
QString fileName() const; QString fileName() const;
@ -40,6 +42,8 @@ signals:
void onToggleMark(int line); void onToggleMark(int line);
void onFunctionTip(const QString &tip); void onFunctionTip(const QString &tip);
void need2Reload();
public slots: public slots:
void setReadOnly(bool b); void setReadOnly(bool b);
bool openFile(const QString &filename); bool openFile(const QString &filename);
@ -57,6 +61,8 @@ private:
private: private:
CodeEdit *m_editor = nullptr; CodeEdit *m_editor = nullptr;
QString m_fileName; QString m_fileName;
QFileSystemWatcher _watcher;
}; };
#endif // SCRIPTEDITOR_H #endif // SCRIPTEDITOR_H

View File

@ -17,17 +17,20 @@
#include "scriptingconsole.h" #include "scriptingconsole.h"
#include "QConsoleWidget/QConsoleIODevice.h" #include "QConsoleWidget/QConsoleIODevice.h"
#include "class/logger.h" #include "class/scriptmachine.h"
#include "class/scriptconsolemachine.h"
#include "class/scriptsettings.h" #include "class/scriptsettings.h"
#include "class/skinmanager.h" #include "class/skinmanager.h"
#include "class/wingmessagebox.h"
#include "model/codecompletionmodel.h" #include "model/codecompletionmodel.h"
#include "utilities.h"
#include <QApplication> #include <QApplication>
#include <QClipboard>
#include <QColor> #include <QColor>
#include <QIcon> #include <QIcon>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu> #include <QMenu>
#include <QMimeData>
#include <QRegularExpression> #include <QRegularExpression>
#include <QTextBlock> #include <QTextBlock>
@ -68,7 +71,7 @@ void ScriptingConsole::handleReturnKey() {
// start new block // start new block
appendPlainText(QString()); appendPlainText(QString());
dontHighlightLastLine(); dontHighlightLastLine(true);
setMode(Output); setMode(Output);
QTextCursor textCursor = this->textCursor(); QTextCursor textCursor = this->textCursor();
@ -84,129 +87,145 @@ void ScriptingConsole::handleReturnKey() {
if (iodevice_->isOpen()) if (iodevice_->isOpen())
iodevice_->consoleWidgetInput(code); iodevice_->consoleWidgetInput(code);
emit consoleCommand(code); if (!_isWaitingRead) {
emit consoleCommand(code);
}
} }
} }
void ScriptingConsole::init() { void ScriptingConsole::init() {
_getInputFn = std::bind(&ScriptingConsole::getInput, this); _getInputFn = std::bind(&ScriptingConsole::getInput, this);
_sp = new ScriptConsoleMachine(_getInputFn, this);
connect(_sp, &ScriptConsoleMachine::onClearConsole, this,
&ScriptingConsole::clear);
connect(this, &ScriptingConsole::abortEvaluation, _sp,
&ScriptConsoleMachine::abortScript);
connect(
_sp, &ScriptConsoleMachine::onOutput, this,
[=](ScriptConsoleMachine::MessageType type,
const ScriptConsoleMachine::MessageInfo &message) {
// <type, <row, col>>
static QPair<ScriptConsoleMachine::MessageType, QPair<int, int>>
lastInfo{ScriptConsoleMachine::MessageType::Print, {-1, -1}};
auto doc = this->document();
auto lastLine = doc->lastBlock();
auto isNotBlockStart = !lastLine.text().isEmpty();
auto fmtMsg = [](const ScriptConsoleMachine::MessageInfo &message)
-> QString {
if (message.row <= 0 || message.col <= 0) {
return message.message;
} else {
return QStringLiteral("(") + QString::number(message.row) +
QStringLiteral(", ") + QString::number(message.col) +
QStringLiteral(") ") + message.message;
}
};
auto isMatchLast =
[](ScriptConsoleMachine::MessageType type,
const ScriptConsoleMachine::MessageInfo &message) -> bool {
if (message.row < 0 || message.col < 0) {
return false;
}
return lastInfo.first == type &&
lastInfo.second.first == message.row &&
lastInfo.second.second == message.col;
};
switch (type) {
case ScriptMachine::MessageType::Info:
if (isMatchLast(type, message)) {
stdOut(message.message);
} else {
if (isNotBlockStart) {
newLine();
}
stdOut(tr("[Info]") + fmtMsg(message));
}
flush();
break;
case ScriptMachine::MessageType::Warn:
if (isMatchLast(type, message)) {
stdWarn(message.message);
} else {
if (isNotBlockStart) {
newLine();
}
stdWarn(tr("[Warn]") + fmtMsg(message));
}
flush();
break;
case ScriptMachine::MessageType::Error:
if (isMatchLast(type, message)) {
stdErr(message.message);
} else {
if (isNotBlockStart) {
newLine();
}
stdErr(tr("[Error]") + fmtMsg(message));
}
flush();
break;
case ScriptMachine::MessageType::Print:
if (lastInfo.first != type) {
newLine();
}
// If running ouput in the console,
// otherwise logging.
if (_sp->isRunning()) {
stdOut(message.message);
} else {
Logger::logPrint(Logger::packDebugStr(
packUpLoggingStr(message.message)));
}
break;
}
lastInfo.first = type;
lastInfo.second = qMakePair(message.row, message.col);
});
connect(this, &QConsoleWidget::consoleCommand, this, connect(this, &QConsoleWidget::consoleCommand, this,
&ScriptingConsole::runConsoleCommand); &ScriptingConsole::runConsoleCommand);
auto cm = new AsConsoleCompletion(_sp->engine(), this); auto cm = new AsConsoleCompletion(this);
connect(cm, &AsCompletion::onFunctionTip, this, connect(cm, &AsCompletion::onFunctionTip, this,
&ScriptingConsole::onFunctionTip); &ScriptingConsole::onFunctionTip);
} }
void ScriptingConsole::clearConsole() { void ScriptingConsole::clearConsole() {
setMode(Output); setMode(Output);
auto cur = this->textCursor();
auto off = cur.position() - this->currentHeaderPos();
auto lastCmd = this->currentCommandLine();
auto dis = lastCmd.length() - off;
clear(); clear();
appendCommandPrompt(lastCommandPrompt());
if (lastCommandPrompt()) {
auto lines = _codes.split('\n');
auto pl = lines.begin();
appendCommandPrompt(false);
writeStdOut(*pl);
pl++;
for (; pl != lines.end(); pl++) {
appendCommandPrompt(true);
writeStdOut(*pl);
}
appendCommandPrompt(true);
} else {
appendCommandPrompt(false);
}
setMode(Input); setMode(Input);
replaceCommandLine(lastCmd);
cur = this->textCursor();
cur.movePosition(QTextCursor::EndOfBlock);
cur.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, dis);
setTextCursor(cur);
} }
void ScriptingConsole::processKeyEvent(QKeyEvent *e) { keyPressEvent(e); } void ScriptingConsole::processKeyEvent(QKeyEvent *e) { keyPressEvent(e); }
void ScriptingConsole::onOutput(const ScriptMachine::MessageInfo &message) {
// <type, <row, col>>
static QPair<ScriptMachine::MessageType, QPair<int, int>> lastInfo{
ScriptMachine::MessageType::Print, {-1, -1}};
auto doc = this->document();
auto lastLine = doc->lastBlock();
auto isNotBlockStart = !lastLine.text().isEmpty();
auto fmtMsg = [](const ScriptMachine::MessageInfo &message) -> QString {
if (message.row <= 0 || message.col <= 0) {
return message.message;
} else {
return QStringLiteral("(") + QString::number(message.row) +
QStringLiteral(", ") + QString::number(message.col) +
QStringLiteral(")") + message.message;
}
};
auto isMatchLast = [](const ScriptMachine::MessageInfo &message) -> bool {
if (message.row < 0 || message.col < 0) {
return false;
}
return lastInfo.first == message.type &&
lastInfo.second.first == message.row &&
lastInfo.second.second == message.col;
};
switch (message.type) {
case ScriptMachine::MessageType::Info:
if (isMatchLast(message)) {
stdOut(message.message);
} else {
if (isNotBlockStart) {
newLine();
}
stdOut(tr("[Info]") + fmtMsg(message));
}
flush();
break;
case ScriptMachine::MessageType::Warn:
if (isMatchLast(message)) {
stdWarn(message.message);
} else {
if (isNotBlockStart) {
newLine();
}
stdWarn(tr("[Warn]") + fmtMsg(message));
}
flush();
break;
case ScriptMachine::MessageType::Error:
if (isMatchLast(message)) {
stdErr(message.message);
} else {
if (isNotBlockStart) {
newLine();
}
stdErr(tr("[Error]") + fmtMsg(message));
}
flush();
break;
case ScriptMachine::MessageType::Print:
if (lastInfo.first != message.type && isNotBlockStart) {
newLine();
}
stdOut(message.message);
break;
}
lastInfo.first = message.type;
lastInfo.second = qMakePair(message.row, message.col);
}
void ScriptingConsole::abortCurrentCode() {
setMode(Output);
_codes.clear();
appendCommandPrompt();
setMode(Input);
}
void ScriptingConsole::applyScriptSettings() { void ScriptingConsole::applyScriptSettings() {
auto &set = ScriptSettings::instance(); auto &set = ScriptSettings::instance();
auto dfont = QFont(set.consoleFontFamily()); auto dfont = QFont(set.consoleFontFamily());
dfont.setPointSize(set.consoleFontSize()); dfont.setPointSize(set.consoleFontSize());
auto thname = set.editorTheme(); auto thname = set.consoleTheme();
if (thname.isEmpty()) { if (thname.isEmpty()) {
switch (SkinManager::instance().currentTheme()) { switch (SkinManager::instance().currentTheme()) {
case SkinManager::Theme::Dark: case SkinManager::Theme::Dark:
@ -232,8 +251,94 @@ void ScriptingConsole::applyScriptSettings() {
void ScriptingConsole::runConsoleCommand(const QString &code) { void ScriptingConsole::runConsoleCommand(const QString &code) {
auto exec = code.trimmed(); auto exec = code.trimmed();
if (exec.endsWith('\\')) { if (exec == QStringLiteral("#ls")) {
auto &ins = ScriptMachine::instance();
auto mod = ins.module(ScriptMachine::Interactive);
if (mod) {
auto total = mod->GetGlobalVarCount();
setMode(Output);
if (total == 0) {
stdOut("<none>");
} else {
auto &sm = ScriptMachine::instance();
for (asUINT i = 0; i < total; ++i) {
const char *name;
int typeID;
auto decl = mod->GetGlobalVarDeclaration(i);
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);
}
}
}
_codes.clear();
appendCommandPrompt();
setMode(Input);
}
} else if (exec.startsWith(QStringLiteral("#del"))) {
// this is special command
auto &ins = ScriptMachine::instance();
auto mod = ins.module(ScriptMachine::Interactive);
if (mod) {
// first check whether contains \n
auto idx = exec.indexOf('\n');
if (idx >= 0) {
setMode(Output);
stdErr(tr("InvalidDelCmd"));
} else {
// ok, then tokens should be devided by the space
exec.remove(0, 4);
auto vars = exec.split(' ', Qt::SkipEmptyParts);
QList<asUINT> indices;
// then check
setMode(Output);
for (auto &v : vars) {
auto idx = mod->GetGlobalVarIndexByName(v.toUtf8());
if (idx >= 0) {
indices.append(idx);
} else {
stdWarn(tr("NotFoundIgnore:") + v);
}
}
std::sort(indices.begin(), indices.end(), std::greater<int>());
// ok, remove
for (auto &i : indices) {
mod->RemoveGlobalVar(i);
}
}
}
_codes.clear();
appendCommandPrompt();
setMode(Input);
} else if (exec == QStringLiteral("#cls")) {
auto &ins = ScriptMachine::instance();
auto mod = ins.module(ScriptMachine::Interactive);
if (mod) {
auto total = mod->GetGlobalVarCount();
if (total) {
asUINT i = total;
do {
--i;
mod->RemoveGlobalVar(i);
} while (i);
}
}
_codes.clear();
appendCommandPrompt();
setMode(Input);
} else if (exec.endsWith('\\')) {
static QRegularExpression ex(QStringLiteral("[\\\\\\s]+$")); static QRegularExpression ex(QStringLiteral("[\\\\\\s]+$"));
_codes.append('\n');
_codes += exec.remove(ex); _codes += exec.remove(ex);
setMode(Output); setMode(Output);
appendCommandPrompt(true); appendCommandPrompt(true);
@ -241,8 +346,8 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
} else { } else {
setMode(Output); setMode(Output);
_codes += exec; _codes += exec;
if (!_sp->executeCode(_codes)) { ScriptMachine::instance().executeCode(ScriptMachine::Interactive,
} _codes);
_codes.clear(); _codes.clear();
appendCommandPrompt(); appendCommandPrompt();
setMode(Input); setMode(Input);
@ -250,11 +355,18 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
} }
QString ScriptingConsole::getInput() { QString ScriptingConsole::getInput() {
auto &s = consoleStream();
appendCommandPrompt(true); appendCommandPrompt(true);
setMode(Input); setMode(Input);
consoleStream().device()->waitForReadyRead(-1); s.status();
auto d = s.device();
auto ba = d->bytesAvailable();
d->skip(ba);
_isWaitingRead = true;
d->waitForReadyRead(-1);
QString instr; QString instr;
consoleStream() >> instr; s >> instr;
_isWaitingRead = false;
setMode(Output); setMode(Output);
return instr; return instr;
} }
@ -277,35 +389,115 @@ void ScriptingConsole::onCompletion(const QModelIndex &index) {
if (selfdata.type == CodeInfoTip::Type::Function || if (selfdata.type == CodeInfoTip::Type::Function ||
selfdata.type == CodeInfoTip::Type::ClsFunction) { selfdata.type == CodeInfoTip::Type::ClsFunction) {
auto args = selfdata.addinfo.value(CodeInfoTip::Args); auto args = selfdata.addinfo.value(CodeInfoTip::Args);
auto cursor = textCursor();
cursor.insertText(QStringLiteral("()")); auto cur = textCursor();
if (!args.isEmpty()) { cur.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
cursor.movePosition(QTextCursor::Left); auto ch = cur.selectedText();
setTextCursor(cursor); if (ch.isEmpty() || ch.front().isSpace()) {
auto cursor = textCursor();
cursor.insertText(QStringLiteral("()"));
if (!args.isEmpty()) {
cursor.movePosition(QTextCursor::Left);
setTextCursor(cursor);
}
} else {
auto cursor = textCursor();
cursor.insertText(QStringLiteral("("));
} }
} }
} }
QString ScriptingConsole::currentCodes() const { void ScriptingConsole::paste() {
return _codes + currentCommandLine(); if (ScriptMachine::instance().isRunning(ScriptMachine::Interactive)) {
return;
}
const QMimeData *const clipboard = QApplication::clipboard()->mimeData();
const QString text = clipboard->text();
if (!text.isEmpty()) {
if (text.indexOf('\n') < 0) {
if (isCursorInEditZone()) {
auto cursor = this->textCursor();
cursor.insertText(text);
} else {
replaceCommandLine(text);
}
} else {
auto ret = WingMessageBox::question(
nullptr, tr("MultiCodeCanNotUndo"), text);
if (ret == QMessageBox::No) {
return;
}
auto lines = text.split('\n');
if (lines.isEmpty()) {
return;
}
setMode(Output);
auto pl = lines.begin();
auto pend = std::prev(lines.end());
writeStdOut(*pl);
pl++;
for (; pl != pend; pl++) {
appendCommandPrompt(true);
writeStdOut(*pl);
}
appendCommandPrompt(true);
setMode(Input);
replaceCommandLine(*pl);
lines.removeLast();
_codes = lines.join('\n');
}
}
} }
ScriptMachine *ScriptingConsole::machine() const { return _sp; } bool ScriptingConsole::isTerminal() const { return _isTerminal; }
ScriptConsoleMachine *ScriptingConsole::consoleMachine() const { return _sp; } void ScriptingConsole::setIsTerminal(bool newIsTerminal) {
_isTerminal = newIsTerminal;
}
QString ScriptingConsole::currentCodes() const {
QTextCursor textCursor = this->textCursor();
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
return _codes + textCursor.selectedText();
}
void ScriptingConsole::contextMenuEvent(QContextMenuEvent *event) { void ScriptingConsole::contextMenuEvent(QContextMenuEvent *event) {
QMenu menu(this); QMenu menu(this);
menu.addAction(QIcon(QStringLiteral(":/qeditor/copy.png")), tr("Copy"), auto a = menu.addAction(QIcon(QStringLiteral(":/qeditor/copy.png")),
QKeySequence(QKeySequence::Copy), this, tr("Copy"), QKeySequence(QKeySequence::Copy), this,
&ScriptingConsole::copy); &ScriptingConsole::copy);
menu.addAction(QIcon(QStringLiteral(":/qeditor/cut.png")), tr("Cut"), a->setShortcutContext(Qt::WidgetShortcut);
QKeySequence(QKeySequence::Cut), this, a = menu.addAction(QIcon(QStringLiteral(":/qeditor/cut.png")), tr("Cut"),
&ScriptingConsole::cut); QKeySequence(QKeySequence::Cut), this,
menu.addAction(QIcon(QStringLiteral(":/qeditor/paste.png")), tr("Paste"), &ScriptingConsole::cut);
QKeySequence(QKeySequence::Paste), this, a->setShortcutContext(Qt::WidgetShortcut);
&ScriptingConsole::paste); a = menu.addAction(QIcon(QStringLiteral(":/qeditor/paste.png")),
tr("Paste"), QKeySequence(QKeySequence::Paste), this,
&ScriptingConsole::paste);
a->setShortcutContext(Qt::WidgetShortcut);
if (_isTerminal) {
a = menu.addAction(ICONRES(QStringLiteral("del")), tr("Clear"),
QKeySequence(Qt::ControlModifier | Qt::Key_L), this,
&ScriptingConsole::clearConsole);
a->setShortcutContext(Qt::WidgetShortcut);
menu.addSeparator();
a = menu.addAction(ICONRES(QStringLiteral("dbgstop")),
tr("AbortScript"),
QKeySequence(Qt::ControlModifier | Qt::Key_Q), []() {
ScriptMachine::instance().abortScript(
ScriptMachine::Background);
});
a->setShortcutContext(Qt::WidgetShortcut);
} else {
a = menu.addAction(ICONRES(QStringLiteral("del")), tr("Clear"),
QKeySequence(Qt::ControlModifier | Qt::Key_L), this,
&ScriptingConsole::clear);
a->setShortcutContext(Qt::WidgetShortcut);
}
menu.exec(event->globalPos()); menu.exec(event->globalPos());
} }

Some files were not shown because too many files have changed in this diff Show More