feat: 更好的代码填充;自动重载文件相关;

This commit is contained in:
寂静的羽夏 2025-04-24 21:10:54 +08:00
parent f59755e3f0
commit 2ee3051a7d
13 changed files with 838 additions and 633 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,7 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
auto engine = dic->GetEngine(); auto engine = dic->GetEngine();
s << " ["; s << " {";
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++) {
@ -88,7 +88,7 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
if (n < dic->GetSize() - 1) if (n < dic->GetSize() - 1)
s << ", "; s << ", ";
} }
s << "]"; s << "}";
return str; return str;
} }

View File

@ -154,11 +154,6 @@ bool AsCompletion::processTrigger(const QString &trigger,
auto code = content.toUtf8(); auto code = content.toUtf8();
QList<CodeInfoTip> nodes; QList<CodeInfoTip> nodes;
QList<CodeInfoTip> docNodes;
if (m_parseDocument) {
docNodes = parseDocument();
}
if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) { if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) {
clearFunctionTip(); clearFunctionTip();
@ -226,24 +221,35 @@ bool AsCompletion::processTrigger(const QString &trigger,
return false; 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 || if (etoken.type == asTC_VALUE || etoken.type == asTC_COMMENT ||
etoken.type == asTC_UNKNOWN) { etoken.type == asTC_UNKNOWN) {
popup()->hide(); popup()->hide();
return false; return false;
} }
if (trigger.isEmpty() && popup()->isVisible()) {
setCompletionPrefix(prefix);
return true;
}
QList<CodeInfoTip> docNodes;
if (m_parseDocument) {
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, docNodes); applyEmptyNsNode(nodes, docNodes);
} else { } else {
etoken = tokens.back(); // checking later etoken = tokens.back(); // checking later
} }
} else {
prefix.clear();
} }
if (nodes.isEmpty()) { if (nodes.isEmpty()) {
@ -266,8 +272,52 @@ bool AsCompletion::processTrigger(const QString &trigger,
} }
if (trigger == *DOT_TRIGGER) { if (trigger == *DOT_TRIGGER) {
// member guessing ? // member type guessing ? basic match is enough. (>n<)
applyClassNodes(nodes); auto isBasicType = [](const QString &type) {
static QStringList basicType{
"int", "int8", "int16", "int32", "int64",
"uint", "uint8", "uint16", "uint32", "uint64",
"float", "double", "byte"};
return basicType.contains(type);
};
auto clsNodes = parser.headerNodes();
// 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;
}
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 type inference is not supported.
// PRs will be welcomed !!!
if (isBasicType(retType)) {
popup()->hide();
return false;
}
nodes.append(clsNodes.value(retType));
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) {
@ -368,6 +418,7 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
va.dontAddGlobal = true; va.dontAddGlobal = true;
va.name = var.name; va.name = var.name;
va.nameSpace = QString::fromUtf8(var.scope.join("::")); va.nameSpace = QString::fromUtf8(var.scope.join("::"));
va.addinfo.insert(CodeInfoTip::RetType, var.type);
va.type = CodeInfoTip::Type::Variable; va.type = CodeInfoTip::Type::Variable;
ret.append(va); ret.append(va);
} }
@ -389,17 +440,47 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
} }
break; break;
case QAsCodeParser::SymbolType::TypeDef: case QAsCodeParser::SymbolType::TypeDef:
tip.type = CodeInfoTip::Type::KeyWord; tip.type = CodeInfoTip::Type::TypeDef;
break; break;
case QAsCodeParser::SymbolType::Variable: case QAsCodeParser::SymbolType::Variable:
tip.addinfo.insert(CodeInfoTip::RetType, sym.type);
tip.type = CodeInfoTip::Type::Variable; tip.type = CodeInfoTip::Type::Variable;
break; break;
case QAsCodeParser::SymbolType::Class: case QAsCodeParser::SymbolType::Class:
case QAsCodeParser::SymbolType::Interface: case QAsCodeParser::SymbolType::Interface:
tip.type = CodeInfoTip::Type::Class;
for (auto &mem : sym.children) { for (auto &mem : sym.children) {
// TODO 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; break;
case QAsCodeParser::SymbolType::Invalid: case QAsCodeParser::SymbolType::Invalid:
case QAsCodeParser::SymbolType::Import: case QAsCodeParser::SymbolType::Import:

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 {

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) {
@ -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;

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

@ -119,12 +119,26 @@ QAsCodeParser::parseIntell(qsizetype offset,
continue; continue;
} }
break; break;
case SymbolType::Class: case SymbolType::Class: {
sym.children = parseClassContent(offset, sym.scope, seg.codes); auto syms =
break; parseClassContent(offset - seg.offset, sym.scope, seg.codes);
case SymbolType::Interface: // TODO: PRS, 'cause i have no need to code-complete a class
sym.children = parseInterfaceContent(offset, sym.scope, seg.codes); sym.inherit = syms.first;
break; sym.children = syms.second;
if (offset > seg.offset && offset < seg.end()) {
ret.append(syms.second);
}
} break;
case SymbolType::Interface: {
auto syms = parseInterfaceContent(offset - seg.offset, sym.scope,
seg.codes);
// TODO: PRS, 'cause i have no need to code-complete an interface
sym.inherit = syms.first;
sym.children = syms.second;
if (offset > seg.offset && offset < seg.end()) {
ret.append(syms.second);
}
} break;
case SymbolType::Invalid: case SymbolType::Invalid:
case SymbolType::Import: case SymbolType::Import:
continue; continue;
@ -510,7 +524,8 @@ QAsCodeParser::parseStatementBlock(const QByteArrayList &ns,
QList<QAsCodeParser::Symbol> ret; QList<QAsCodeParser::Symbol> ret;
for (auto &symlist : syms) { for (auto &symlist : syms) {
for (auto &sym : symlist) { for (auto &sym : symlist) {
if (sym.symtype == SymbolType::Variable) { if (sym.symtype == SymbolType::Variable &&
!sym.type.isEmpty()) {
auto var = sym.name; auto var = sym.name;
auto n = std::find_if( auto n = std::find_if(
ret.begin(), ret.end(), ret.begin(), ret.end(),
@ -940,13 +955,14 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseFuncDef() {
auto begin = t1.pos; auto begin = t1.pos;
skipCodeBlock(); skipCodeBlock();
getToken(&t1); getToken(&t1);
rewindTo(&t1);
auto end = t1.pos; auto end = t1.pos;
// seg.name is empty // seg.name is empty
seg.scope = currentNs; seg.scope = currentNs;
seg.offset = begin; seg.offset = begin;
seg.type = SymbolType::FnDef; seg.type = SymbolType::FnDef;
seg.codes = _code.sliced(begin, end - begin + 1); seg.codes = _code.sliced(begin, end - begin);
return seg; return seg;
} }
@ -1027,6 +1043,7 @@ void QAsCodeParser::superficiallyParseVarInit() {
} while (indentParan || indentBrace || } while (indentParan || indentBrace ||
(t.type != ttListSeparator && t.type != ttEndStatement && (t.type != ttListSeparator && t.type != ttEndStatement &&
t.type != ttEndStatementBlock)); t.type != ttEndStatementBlock));
rewindTo(&t);
} else if (t.type == ttOpenParenthesis) { } else if (t.type == ttOpenParenthesis) {
sToken start = t; sToken start = t;
@ -1308,6 +1325,7 @@ QAsCodeParser::CodeSegment QAsCodeParser::parseTypedef() {
auto begin = token.pos; auto begin = token.pos;
skipCodeBlock(); skipCodeBlock();
getToken(&token); getToken(&token);
rewindTo(&token);
auto end = token.pos; auto end = token.pos;
// seg.name is empty // seg.name is empty
@ -1423,22 +1441,27 @@ QAsCodeParser::parseGlobalVarDecls(const QByteArrayList &ns,
return parseDeclaration(ns, false, true); return parseDeclaration(ns, false, true);
} }
QAsCodeParser::CodeSegment QAsCodeParser::parseFunctionMethod() { QAsCodeParser::CodeSegment QAsCodeParser::parseFunctionMethod(Visiblity &vis) {
CodeSegment seg; CodeSegment seg;
sToken t1; sToken t1;
getToken(&t1); getToken(&t1);
vis = Visiblity::Public;
// A class method can start with 'private' or 'protected' // A class method can start with 'private' or 'protected'
if (t1.type == ttPrivate) { if (t1.type == ttPrivate) {
rewindTo(&t1); rewindTo(&t1);
parseToken(ttPrivate); parseToken(ttPrivate);
getToken(&t1); getToken(&t1);
vis = Visiblity::Private;
} else if (t1.type == ttProtected) { } else if (t1.type == ttProtected) {
rewindTo(&t1); rewindTo(&t1);
parseToken(ttProtected); parseToken(ttProtected);
getToken(&t1); getToken(&t1);
vis = Visiblity::Protected;
} }
if (_isSyntaxError) if (_isSyntaxError)
return seg; return seg;
@ -1530,12 +1553,13 @@ QAsCodeParser::parseFuncDefContent(const QByteArrayList &ns,
return parseFuncDefContent(ns); return parseFuncDefContent(ns);
} }
QList<QAsCodeParser::Symbol> QPair<QByteArrayList, QList<QAsCodeParser::Symbol>>
QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns, QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
const QByteArray &code) { const QByteArray &code) {
reset(); reset();
_code = code; _code = code;
QByteArrayList inhertSyms;
QList<Symbol> syms; QList<Symbol> syms;
sToken t; sToken t;
@ -1544,32 +1568,30 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
// Optional list of interfaces that are being implemented and classes that // Optional list of interfaces that are being implemented and classes that
// are being inherited // are being inherited
if (t.type == ttColon) { if (t.type == ttColon) {
Symbol inhertSym; QByteArray inhertSym;
// assuming it as an interface // assuming it as an interface
inhertSym.symtype = SymbolType::Interface; inhertSym = parseOptionalScope().join("::");
if (!inhertSym.isEmpty()) {
Symbol isym; inhertSym += "::";
isym.scope = parseOptionalScope(); }
isym.name = getSymbolString(parseIdentifier()); inhertSym += getSymbolString(parseIdentifier());
isym.symtype = SymbolType::Class; // assuming it as a class inhertSyms.append(inhertSym);
inhertSym.children.append(isym);
getToken(&t); getToken(&t);
while (t.type == ttListSeparator) { while (t.type == ttListSeparator) {
isym.scope = parseOptionalScope(); inhertSym = parseOptionalScope().join("::");
isym.name = getSymbolString(parseIdentifier()); if (!inhertSym.isEmpty()) {
inhertSym.children.append(isym); inhertSym += "::";
}
inhertSym += getSymbolString(parseIdentifier());
inhertSyms.append(inhertSym);
getToken(&t); getToken(&t);
} }
syms.append(inhertSym);
} }
if (t.type != ttStartStatementBlock) { if (t.type != ttStartStatementBlock) {
rewindErrorTo(&t); rewindErrorTo(&t);
return syms; return {inhertSyms, syms};
} }
// Parse properties // Parse properties
@ -1581,11 +1603,11 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
auto fndef = parseFuncDefContent(ns); auto fndef = parseFuncDefContent(ns);
syms.append(fndef); syms.append(fndef);
} else if (isFuncDecl(true)) { } else if (isFuncDecl(true)) {
auto fn = parseFunctionMethod(); Symbol sym;
auto fn = parseFunctionMethod(sym.vis);
// add function symbols // add function symbols
Symbol sym; sym.symtype = SymbolType::Function;
sym.symtype = fn.type;
sym.scope = fn.scope; sym.scope = fn.scope;
sym.offset = fn.offset; sym.offset = fn.offset;
sym.name = fn.name; sym.name = fn.name;
@ -1595,7 +1617,8 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
// deep parsing // deep parsing
if (offset >= fn.offset && offset < fn.end()) { if (offset >= fn.offset && offset < fn.end()) {
auto ss = parseStatementBlock(fn.scope, fn.codes, offset); auto ss =
parseStatementBlock(fn.scope, fn.codes, offset - fn.offset);
syms.append(ss); syms.append(ss);
} }
} else if (isVirtualPropertyDecl()) { } else if (isVirtualPropertyDecl()) {
@ -1609,11 +1632,11 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
getToken(&t); getToken(&t);
else { else {
rewindErrorTo(&t); rewindErrorTo(&t);
return syms; return {inhertSyms, syms};
} }
if (_isSyntaxError) if (_isSyntaxError)
return syms; return {inhertSyms, syms};
getToken(&t); getToken(&t);
rewindTo(&t); rewindTo(&t);
@ -1622,15 +1645,16 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
getToken(&t); getToken(&t);
if (t.type != ttEndStatementBlock) { if (t.type != ttEndStatementBlock) {
rewindErrorTo(&t); rewindErrorTo(&t);
return syms; return {inhertSyms, syms};
} }
return syms; return {inhertSyms, syms};
} }
QList<QAsCodeParser::Symbol> QPair<QByteArrayList, QList<QAsCodeParser::Symbol>>
QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns, QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns,
const QByteArray &code) { const QByteArray &code) {
QByteArrayList inhertSyms;
QList<Symbol> syms; QList<Symbol> syms;
sToken t; sToken t;
@ -1638,12 +1662,22 @@ QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns,
getToken(&t); getToken(&t);
// Can optionally have a list of interfaces that are inherited // Can optionally have a list of interfaces that are inherited
if (t.type == ttColon) { if (t.type == ttColon) {
parseOptionalScope(); QByteArray inhertSym;
parseIdentifier();
inhertSym = parseOptionalScope().join("::");
if (!inhertSym.isEmpty()) {
inhertSym += "::";
}
inhertSym += getSymbolString(parseIdentifier());
inhertSyms.append(inhertSym);
getToken(&t); getToken(&t);
while (t.type == ttListSeparator) { while (t.type == ttListSeparator) {
parseOptionalScope(); inhertSym = parseOptionalScope().join("::");
parseIdentifier(); if (!inhertSym.isEmpty()) {
inhertSym += "::";
}
inhertSym += getSymbolString(parseIdentifier());
inhertSyms.append(inhertSym);
getToken(&t); getToken(&t);
} }
} }
@ -1670,7 +1704,7 @@ QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns,
} }
if (_isSyntaxError) if (_isSyntaxError)
return syms; return {inhertSyms, syms};
getToken(&t); getToken(&t);
rewindTo(&t); rewindTo(&t);
@ -1679,10 +1713,10 @@ QAsCodeParser::parseInterfaceContent(qsizetype offset, const QByteArrayList &ns,
getToken(&t); getToken(&t);
if (t.type != ttEndStatementBlock) { if (t.type != ttEndStatementBlock) {
rewindErrorTo(&t); rewindErrorTo(&t);
return syms; return {inhertSyms, syms};
} }
return syms; return {inhertSyms, syms};
} }
QAsCodeParser::Symbol QAsCodeParser::parseInterfaceMethod() { QAsCodeParser::Symbol QAsCodeParser::parseInterfaceMethod() {

View File

@ -90,6 +90,7 @@ public:
Visiblity vis = QAsCodeParser::Visiblity::Public; Visiblity vis = QAsCodeParser::Visiblity::Public;
QByteArray additonalInfo; // for other additonal info QByteArray additonalInfo; // for other additonal info
QByteArrayList inherit;
QList<Symbol> children; QList<Symbol> children;
}; };
@ -134,7 +135,7 @@ private:
CodeSegment parseInterface(); CodeSegment parseInterface();
CodeSegment parseFuncDef(); CodeSegment parseFuncDef();
CodeSegment parseFunction(); CodeSegment parseFunction();
CodeSegment parseFunctionMethod(); CodeSegment parseFunctionMethod(Visiblity &vis);
private: private:
// parse tokens // parse tokens
@ -172,12 +173,13 @@ private:
Symbol parseFuncDefContent(const QByteArrayList &ns); Symbol parseFuncDefContent(const QByteArrayList &ns);
QList<Symbol> parseClassContent(qsizetype offset, const QByteArrayList &ns, QPair<QByteArrayList, QList<Symbol>>
const QByteArray &code); parseClassContent(qsizetype offset, const QByteArrayList &ns,
const QByteArray &code);
QList<Symbol> parseInterfaceContent(qsizetype offset, QPair<QByteArrayList, QList<Symbol>>
const QByteArrayList &ns, parseInterfaceContent(qsizetype offset, const QByteArrayList &ns,
const QByteArray &code); const QByteArray &code);
QList<Symbol> parseStatementBlock(const QByteArrayList &ns, QList<Symbol> parseStatementBlock(const QByteArrayList &ns,
const QByteArray &code, qsizetype end); const QByteArray &code, qsizetype end);

View File

@ -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
@ -284,6 +287,9 @@ ErrFile EditorView::newFile(size_t index) {
if (isCloneFile()) { if (isCloneFile()) {
return ErrFile::ClonedFile; return ErrFile::ClonedFile;
} }
if (!m_fileName.isEmpty()) {
_watcher.removePath(m_fileName);
}
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,10 @@ ErrFile EditorView::openFile(const QString &filename) {
return ErrFile::Permission; return ErrFile::Permission;
} }
if (!m_fileName.isEmpty()) {
_watcher.removePath(m_fileName);
}
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 +345,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);
_watcher.addPath(m_fileName);
} }
return ErrFile::Success; return ErrFile::Success;
@ -372,6 +384,10 @@ ErrFile EditorView::openExtFile(const QString &ext, const QString &file) {
return ErrFile::Error; return ErrFile::Error;
} }
if (!m_fileName.isEmpty()) {
_watcher.removePath(m_fileName);
}
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);
@ -562,10 +578,14 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
file.close(); file.close();
if (!isExport) { if (!isExport) {
if (!m_fileName.isEmpty()) {
_watcher.removePath(m_fileName);
}
m_fileName = QFileInfo(fileName).absoluteFilePath(); m_fileName = QFileInfo(fileName).absoluteFilePath();
m_isNewFile = false; m_isNewFile = false;
m_docType = DocumentType::File; m_docType = DocumentType::File;
doc->setDocSaved(); doc->setDocSaved();
_watcher.addPath(m_fileName);
} }
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
adjustPermission(); adjustPermission();

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>
@ -553,6 +554,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;
@ -589,6 +592,7 @@ private:
QReadWriteLock _rwlock; QReadWriteLock _rwlock;
CallTable _viewFns; CallTable _viewFns;
QFileSystemWatcher _watcher;
}; };
#endif // EDITORVIEW_H #endif // EDITORVIEW_H

View File

@ -245,7 +245,8 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
sm.registerCallBack(ScriptMachine::Interactive, callbacks); sm.registerCallBack(ScriptMachine::Interactive, callbacks);
callbacks.getInputFn = [this]() -> QString { callbacks.getInputFn = [this]() -> QString {
return WingInputDialog::getText(this, tr(""), tr("")); return WingInputDialog::getText(this, tr("InputRequest"),
tr("PleaseInput"));
}; };
callbacks.clearFn = [this]() { m_bgScriptOutput->clear(); }; callbacks.clearFn = [this]() { m_bgScriptOutput->clear(); };
callbacks.printMsgFn = callbacks.printMsgFn =
@ -3162,6 +3163,22 @@ void MainWindow::connectEditorView(EditorView *editor) {
connect(editor, &EditorView::sigOnPasteHex, this, &MainWindow::on_pastehex); connect(editor, &EditorView::sigOnPasteHex, this, &MainWindow::on_pastehex);
connect(editor, &EditorView::sigOnPasteFile, this, connect(editor, &EditorView::sigOnPasteFile, this,
&MainWindow::on_pastefile); &MainWindow::on_pastefile);
editor->setProperty("__RELOAD__", false);
connect(editor, &EditorView::need2Reload, this, [editor, this]() {
if (editor->isBigFile()) {
editor->reload();
}
if (currentEditor() == editor) {
auto ret = WingMessageBox::question(this, tr("Reload"),
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
editor->reload();
}
} else {
editor->setProperty("__RELOAD__", true);
}
});
} }
void MainWindow::swapEditor(EditorView *old, EditorView *cur) { void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
@ -3188,6 +3205,15 @@ void MainWindow::swapEditor(EditorView *old, EditorView *cur) {
Q_ASSERT(cur); Q_ASSERT(cur);
auto hexeditor = cur->hexEditor(); auto hexeditor = cur->hexEditor();
auto needReload = cur->property("__RELOAD__").toBool();
if (needReload) {
auto ret = WingMessageBox::question(this, tr("Reload"),
tr("ReloadNeededYesOrNo"));
if (ret == QMessageBox::Yes) {
cur->reload();
}
cur->setProperty("__RELOAD__", false);
}
connect(hexeditor, &QHexView::cursorLocationChanged, this, connect(hexeditor, &QHexView::cursorLocationChanged, this,
&MainWindow::on_locChanged); &MainWindow::on_locChanged);
connect(hexeditor, &QHexView::cursorSelectionChanged, this, connect(hexeditor, &QHexView::cursorSelectionChanged, this,