diff --git a/3rdparty/QHexView/CMakeLists.txt b/3rdparty/QHexView/CMakeLists.txt index 1bd67d8..a133302 100644 --- a/3rdparty/QHexView/CMakeLists.txt +++ b/3rdparty/QHexView/CMakeLists.txt @@ -57,8 +57,6 @@ add_library( document/commands/baseaddrcommand.h document/commands/encodingchangecommand.cpp document/commands/encodingchangecommand.h - document/buffer/qwindriverbuffer.h - document/buffer/qwindriverbuffer.cpp document/qstoragedevice.h document/qstoragedevice.cpp document/qhexcursor.cpp @@ -71,8 +69,6 @@ add_library( document/qhexrenderer.h QHexEdit2/chunks.cpp QHexEdit2/chunks.h - QHexEdit2/chunks_win.cpp - QHexEdit2/chunks_win.h qhexview.h qhexview.cpp) diff --git a/3rdparty/QHexView/QHexEdit2/chunks_win.cpp b/3rdparty/QHexView/QHexEdit2/chunks_win.cpp deleted file mode 100644 index efe8649..0000000 --- a/3rdparty/QHexView/QHexEdit2/chunks_win.cpp +++ /dev/null @@ -1,310 +0,0 @@ -#include "chunks_win.h" - -#ifdef Q_OS_WIN - -#define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffffd00) - -/*this file is modified by wingsummer in order to fit the QHexView*/ - -// ***************************************** Constructors and file settings - -Chunks_win::Chunks_win(QObject *parent) : QObject(parent) {} - -Chunks_win::Chunks_win(const QStorageInfo &ioDevice, QObject *parent) - : QObject(parent) { - setIODevice(ioDevice); -} - -Chunks_win::~Chunks_win() { - if (_handle != INVALID_HANDLE_VALUE) { - CloseHandle(_handle); - } -} - -bool Chunks_win::setIODevice(const QStorageInfo &ioDevice) { - if (ioDevice.isValid()) { - auto device = ioDevice.device(); - auto devicePrefix = QStringLiteral("\\\\.\\"); - QString dd = devicePrefix + - device.mid(devicePrefix.length(), - device.length() - devicePrefix.length() - 1); - - _handle = CreateFileA(dd.toLatin1(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, 0, NULL); - if (_handle == INVALID_HANDLE_VALUE) { - return false; - } - - DISK_GEOMETRY diskGeometry; - DWORD bytesReturned; - if (!DeviceIoControl(_handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, - &diskGeometry, sizeof(diskGeometry), - &bytesReturned, NULL)) { - - CloseHandle(_handle); - return false; - } - - // dont use ioDevice.bytesTotal(), - // because it's use GetDiskFreeSpaceEx API to get - this->CHUNK_SIZE = diskGeometry.BytesPerSector; - _size = diskGeometry.Cylinders.QuadPart * - diskGeometry.TracksPerCylinder * diskGeometry.SectorsPerTrack * - diskGeometry.BytesPerSector; - - } else { - return false; - } - _chunks.clear(); - _pos = 0; - return true; -} - -// ***************************************** Getting data out of Chunks_win - -QByteArray Chunks_win::data(qsizetype pos, qsizetype maxSize) { - qsizetype ioDelta = 0; - qsizetype chunkIdx = 0; - - Chunk_win chunk; - QByteArray buffer; - - // Do some checks and some arrangements - - if (pos >= _size) - return buffer; - - if (maxSize < 0) - maxSize = _size; - else if ((pos + maxSize) > _size) - maxSize = _size - pos; - - while (maxSize > 0) { - chunk.absPos = std::numeric_limits::max(); - bool chunksLoopOngoing = true; - while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) { - // In this section, we track changes before our required data and - // we take the editdet data, if availible. ioDelta is a difference - // counter to justify the read pointer to the original data, if - // data in between was deleted or inserted. - - chunk = _chunks[chunkIdx]; - if (chunk.absPos > pos) - chunksLoopOngoing = false; - else { - chunkIdx += 1; - qsizetype count; - qsizetype chunkOfs = pos - chunk.absPos; - if (qsizetype(maxSize) > chunk.data.size() - chunkOfs) { - count = chunk.data.size() - chunkOfs; - ioDelta += CHUNK_SIZE - chunk.data.size(); - } else - count = maxSize; - if (count > 0) { - buffer += chunk.data.mid(chunkOfs, count); - maxSize -= count; - pos += count; - } - } - } - - if ((maxSize > 0) && (pos < chunk.absPos)) { - // In this section, we read data from the original source. This only - // will happen, whe no copied data is available - - qint64 byteCount; - QByteArray readBuffer; - if (chunk.absPos - pos > qsizetype(maxSize)) - byteCount = maxSize; - else - byteCount = chunk.absPos - pos; - - maxSize -= byteCount; - - // Set the pointer to the start of the sector you want to read - LARGE_INTEGER sectorOffset; - auto sorquot = (pos + ioDelta) / CHUNK_SIZE; - auto sorrem = (pos + ioDelta) % CHUNK_SIZE; - - sectorOffset.QuadPart = sorquot * CHUNK_SIZE; - Q_ASSERT(SetFilePointerEx(_handle, sectorOffset, NULL, FILE_BEGIN)); - - readBuffer.fill(0, CHUNK_SIZE); - DWORD bytesRead; - Q_ASSERT(ReadFile(_handle, readBuffer.data(), CHUNK_SIZE, - &bytesRead, NULL)); - readBuffer = readBuffer.mid(sorrem, byteCount); - buffer += readBuffer; - pos += readBuffer.size(); - } - } - - return buffer; -} - -bool Chunks_win::write(QIODevice *iODevice, qsizetype pos, qsizetype count) { - if (count == -1) - count = _size; - - // fix the bug - bool ok = (iODevice->isOpen() && iODevice->isWritable()) || - iODevice->open(QIODevice::WriteOnly); - if (ok) { - for (auto idx = pos; idx < qsizetype(count); idx += CHUNK_SIZE) { - QByteArray ba = data(idx, CHUNK_SIZE); - iODevice->write(ba); - } - iODevice->close(); - } - return ok; -} - -// ***************************************** Search API - -qsizetype Chunks_win::indexOf(const QByteArray &ba, qsizetype from) { - qsizetype result = -1; - QByteArray buffer; - - for (auto pos = from; (pos < _size) && (result < 0); pos += CHUNK_SIZE) { - buffer = data(pos, CHUNK_SIZE + ba.size() - 1); - int findPos = buffer.indexOf(ba); - if (findPos >= 0) - result = pos + findPos; - } - return result; -} - -qsizetype Chunks_win::lastIndexOf(const QByteArray &ba, qsizetype from) { - qint64 result = -1; - QByteArray buffer; - - for (auto pos = from; (pos > 0) && (result < 0); pos -= CHUNK_SIZE) { - auto sPos = pos - CHUNK_SIZE - ba.size() + 1; - /*if (sPos < 0) - sPos = 0;*/ - buffer = data(sPos, pos - sPos); - int findPos = buffer.lastIndexOf(ba); - if (findPos >= 0) - result = sPos + findPos; - } - return result; -} - -// ***************************************** Char manipulations - -bool Chunks_win::insert(qsizetype pos, char b) { - if (pos > _size) - return false; - qsizetype chunkIdx; - if (pos == _size) { - chunkIdx = getChunkIndex(pos - 1); - } else - chunkIdx = getChunkIndex(pos); - auto posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].data.insert(int(posInBa), b); - _chunks[chunkIdx].dataChanged.insert(int(posInBa), char(1)); - for (int idx = chunkIdx + 1; idx < _chunks.size(); idx++) - _chunks[idx].absPos += 1; - _size += 1; - _pos = pos; - return true; -} - -bool Chunks_win::overwrite(qsizetype pos, char b) { - if (pos >= _size) - return false; - auto chunkIdx = getChunkIndex(pos); - auto posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].data[int(posInBa)] = b; - _chunks[chunkIdx].dataChanged[int(posInBa)] = char(1); - _pos = pos; - return true; -} - -bool Chunks_win::removeAt(qsizetype pos) { - if (pos >= _size) - return false; - auto chunkIdx = getChunkIndex(pos); - auto posInBa = pos - _chunks[chunkIdx].absPos; - _chunks[chunkIdx].data.remove(int(posInBa), 1); - _chunks[chunkIdx].dataChanged.remove(int(posInBa), 1); - for (int idx = chunkIdx + 1; idx < _chunks.size(); idx++) - _chunks[idx].absPos -= 1; - _size -= 1; - _pos = pos; - return true; -} - -// ***************************************** Utility functions - -char Chunks_win::operator[](qsizetype pos) { - auto d = data(pos, 1); - if (d.isEmpty()) - return '0'; - return d.at(0); -} - -qsizetype Chunks_win::pos() { return _pos; } - -qsizetype Chunks_win::size() { return _size; } - -qsizetype Chunks_win::getChunkIndex(qsizetype absPos) { - // This routine checks, if there is already a copied chunk available. If so, - // it returns a reference to it. If there is no copied chunk available, - // original data will be copied into a new chunk. - - qsizetype foundIdx = -1; - qsizetype insertIdx = 0; - qsizetype ioDelta = 0; - - // fix the bug by wingsummer - if (absPos < 0) { - Chunk_win newChunk; - newChunk.data = QByteArray(CHUNK_SIZE, 0); - newChunk.absPos = 0; - newChunk.dataChanged = nullptr; - _chunks.insert(insertIdx, newChunk); - return insertIdx; - } - - for (int idx = 0; idx < _chunks.size(); idx++) { - Chunk_win chunk = _chunks[idx]; - if ((absPos >= chunk.absPos) && - (absPos < (chunk.absPos + chunk.data.size()))) { - foundIdx = idx; - break; - } - if (absPos < chunk.absPos) { - insertIdx = idx; - break; - } - ioDelta += chunk.data.size() - CHUNK_SIZE; - insertIdx = idx + 1; - } - - if (foundIdx == -1) { - Chunk_win newChunk; - auto readAbsPos = absPos - ioDelta; - auto readPos = (readAbsPos & READ_CHUNK_MASK); - - // Set the pointer to the start of the sector you want to read - LARGE_INTEGER sectorOffset; - sectorOffset.QuadPart = readPos; - Q_ASSERT(SetFilePointerEx(_handle, sectorOffset, NULL, FILE_BEGIN)); - - newChunk.data.fill(0, CHUNK_SIZE); - DWORD bytesRead = 0; - Q_ASSERT(ReadFile(_handle, newChunk.data.data(), CHUNK_SIZE, &bytesRead, - NULL)); - newChunk.data.resize(bytesRead); - - newChunk.absPos = absPos - (readAbsPos - readPos); - newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0)); - _chunks.insert(insertIdx, newChunk); - foundIdx = insertIdx; - } - return foundIdx; -} - -#endif diff --git a/3rdparty/QHexView/QHexEdit2/chunks_win.h b/3rdparty/QHexView/QHexEdit2/chunks_win.h deleted file mode 100644 index 0b28594..0000000 --- a/3rdparty/QHexView/QHexEdit2/chunks_win.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef Chunks_winWIN_H -#define Chunks_winWIN_H - -/** \cond docNever */ - -/*! The Chunks_win class is the storage backend for QHexEdit. - * - * When QHexEdit loads data, Chunks_win access them using a QIODevice interface. - * When the app uses a QByteArray interface, QBuffer is used to provide again a - * QIODevice like interface. No data will be changed, therefore Chunks_win opens - * the QIODevice in QIODevice::ReadOnly mode. After every access Chunks_win - * closes the QIODevice, that's why external applications can overwrite files - * while QHexEdit shows them. - * - * When the the user starts to edit the data, Chunks_win creates a local copy of - * a chunk of data (4 kilobytes) and notes all changes there. Parallel to that - * chunk, there is a second chunk, which keep track of which bytes are changed - * and which not. - * - */ - -#include - -// note: this class is only for storage device reading - -#ifdef Q_OS_WIN - -#include -#include - -struct Chunk_win { - QByteArray data; - QByteArray dataChanged; - qsizetype absPos; -}; - -class Chunks_win : public QObject { - Q_OBJECT -public: - // Constructors and file settings - Chunks_win(QObject *parent = nullptr); - Chunks_win(const QStorageInfo &ioDevice, QObject *parent); - - ~Chunks_win(); - - bool setIODevice(const QStorageInfo &ioDevice); - - // Getting data out of Chunks_win - QByteArray data(qsizetype pos = 0, qsizetype maxSize = -1); - bool write(QIODevice *iODevice, qsizetype pos = 0, qsizetype count = -1); - - // Search API - qsizetype indexOf(const QByteArray &ba, qsizetype from); - qsizetype lastIndexOf(const QByteArray &ba, qsizetype from); - - // Char manipulations - bool insert(qsizetype pos, char b); - bool overwrite(qsizetype pos, char b); - bool removeAt(qsizetype pos); - - // Utility functions - char operator[](qsizetype pos); - qsizetype pos(); - qsizetype size(); - -private: - qsizetype getChunkIndex(qsizetype absPos); - QIODevice *_ioDevice; - qsizetype _pos; - qsizetype _size; - qsizetype CHUNK_SIZE; - HANDLE _handle = INVALID_HANDLE_VALUE; - QList _chunks; -}; - -#endif - -#endif // Chunks_win_H diff --git a/3rdparty/QHexView/document/buffer/qwindriverbuffer.cpp b/3rdparty/QHexView/document/buffer/qwindriverbuffer.cpp deleted file mode 100644 index fd28857..0000000 --- a/3rdparty/QHexView/document/buffer/qwindriverbuffer.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "qwindriverbuffer.h" - -#ifdef Q_OS_WIN - -#include "document/qstoragedevice.h" - -/* - * this file is implemented by wingsummer, - * 使用 QHexEdit2 的代码来实现轻松访问上 GB 的文件, - * 该类作者并未实现 - */ - -QWinDriverBuffer::QWinDriverBuffer(QObject *parent) : QHexBuffer(parent) { - _chunks = new Chunks_win(parent); -} - -QWinDriverBuffer::~QWinDriverBuffer() {} - -uchar QWinDriverBuffer::at(qsizetype idx) { - return uchar(_chunks->data(idx, 1)[0]); -} - -qsizetype QWinDriverBuffer::length() const { return _chunks->size(); } - -void QWinDriverBuffer::insert(qsizetype offset, const QByteArray &data) { - for (int i = 0; i < data.length(); i++) { - _chunks->insert(offset + i, data.at(i)); - } -} - -void QWinDriverBuffer::remove(qsizetype offset, qsizetype length) { - for (uint i = 0; i < uint(length); i++) { - _chunks->removeAt(offset + i); - } -} - -QByteArray QWinDriverBuffer::read(qsizetype offset, qsizetype length) { - return _chunks->data(offset, length); -} - -bool QWinDriverBuffer::read(QIODevice *device) { - if (device == nullptr) { - return false; - } - - auto driver = qobject_cast(device); - if (driver == nullptr) { - delete device; - return false; - } - - auto storage = driver->storage(); // only use name - delete device; - - _chunks->setIODevice(storage); - return true; -} - -void QWinDriverBuffer::write(QIODevice *device) { _chunks->write(device); } - -qsizetype QWinDriverBuffer::indexOf(const QByteArray &ba, qsizetype from) { - return _chunks->indexOf(ba, from); -} - -qsizetype QWinDriverBuffer::lastIndexOf(const QByteArray &ba, qsizetype from) { - return _chunks->lastIndexOf(ba, from); -} - -#endif diff --git a/3rdparty/QHexView/document/buffer/qwindriverbuffer.h b/3rdparty/QHexView/document/buffer/qwindriverbuffer.h deleted file mode 100644 index bd6c16f..0000000 --- a/3rdparty/QHexView/document/buffer/qwindriverbuffer.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef QWINDRIVERBUFFER_H -#define QWINDRIVERBUFFER_H - -#include - -#ifdef Q_OS_WIN - -#include "QHexEdit2/chunks_win.h" -#include "qhexbuffer.h" -#include - -class QWinDriverBuffer : public QHexBuffer { - -public: - explicit QWinDriverBuffer(QObject *parent = nullptr); - ~QWinDriverBuffer() override; - uchar at(qsizetype idx) override; - qsizetype length() const override; - void insert(qsizetype offset, const QByteArray &data) override; - void remove(qsizetype offset, qsizetype length) override; - QByteArray read(qsizetype offset, qsizetype length) override; - bool read(QIODevice *device) override; - void write(QIODevice *device) override; - - qsizetype indexOf(const QByteArray &ba, qsizetype from) override; - qsizetype lastIndexOf(const QByteArray &ba, qsizetype from) override; - -private: - Chunks_win *_chunks; - uchar *m_memory; -}; - -#endif - -#endif // QWINDRIVERBUFFER_H diff --git a/3rdparty/QHexView/document/qhexdocument.cpp b/3rdparty/QHexView/document/qhexdocument.cpp index e83ee58..021339e 100644 --- a/3rdparty/QHexView/document/qhexdocument.cpp +++ b/3rdparty/QHexView/document/qhexdocument.cpp @@ -17,7 +17,6 @@ #include #ifdef Q_OS_WIN -#include "buffer/qwindriverbuffer.h" #include "qstoragedevice.h" #endif @@ -558,7 +557,7 @@ QHexDocument *QHexDocument::fromStorageDriver(const QStorageInfo &storage, #ifdef Q_OS_WIN auto f = new QStorageDevice; f->setStorage(storage); - auto hexbuffer = new QWinDriverBuffer(); + auto hexbuffer = new QFileBuffer(); if (hexbuffer->read(f)) { return new QHexDocument(hexbuffer, readonly); } else { diff --git a/3rdparty/QHexView/document/qstoragedevice.cpp b/3rdparty/QHexView/document/qstoragedevice.cpp index b3852eb..4d3f978 100644 --- a/3rdparty/QHexView/document/qstoragedevice.cpp +++ b/3rdparty/QHexView/document/qstoragedevice.cpp @@ -1,7 +1,14 @@ #include "qstoragedevice.h" -#include "qstorageinfo.h" -QStorageDevice::QStorageDevice() : QIODevice() {} +#ifdef Q_OS_WIN + +#include +#include + +QStorageDevice::QStorageDevice(QObject *parent) + : QIODevice(parent), CHUNK_SIZE(0), _size(0) { + _buffer.setTextModeEnabled(false); +} void QStorageDevice::setStorage(const QStorageInfo &storage) { _storage = storage; @@ -9,6 +16,147 @@ void QStorageDevice::setStorage(const QStorageInfo &storage) { QStorageInfo QStorageDevice::storage() const { return _storage; } -qint64 QStorageDevice::readData(char *data, qint64 maxlen) { return -1; } +bool QStorageDevice::isSequential() const { return false; } -qint64 QStorageDevice::writeData(const char *data, qint64 len) { return -1; } +bool QStorageDevice::open(OpenMode mode) { + if (_buffer.isOpen()) { + setErrorString(QStringLiteral("A Storage file is still opened")); + return false; + } + + if (mode == OpenModeFlag::ReadOnly || mode == OpenModeFlag::WriteOnly || + mode == OpenModeFlag::ReadWrite) { + auto device = _storage.device(); + auto devicePrefix = QStringLiteral("\\\\.\\"); + QString dd = devicePrefix + + device.mid(devicePrefix.length(), + device.length() - devicePrefix.length() - 1); + + // Open the physical drive using WinAPI + auto hDevice = + CreateFileW(reinterpret_cast(dd.utf16()), GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, nullptr); + + if (hDevice == INVALID_HANDLE_VALUE) { + qWarning() << "Failed to open device:" << device; + return false; + } + + DISK_GEOMETRY diskGeometry; + DWORD bytesReturned; + if (!DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &diskGeometry, sizeof(diskGeometry), + &bytesReturned, NULL)) { + CloseHandle(hDevice); + return false; + } + + CloseHandle(hDevice); + + this->CHUNK_SIZE = diskGeometry.BytesPerSector; + + // dont use ioDevice.bytesTotal(), + // because it's use GetDiskFreeSpaceEx API to get. + // QFile::size() is zero + _size = diskGeometry.Cylinders.QuadPart * + diskGeometry.TracksPerCylinder * diskGeometry.SectorsPerTrack * + diskGeometry.BytesPerSector; + + if (!_buffer.open(mode)) { + // _buffer.setFileName({}); + return false; + } + + return QIODevice::open(QIODevice::ReadOnly); + } else { + qWarning() << "Only OpenModeFlag::ReadOnly and OpenModeFlag::WriteOnly " + "are supported"; + return false; + } +} + +void QStorageDevice::close() { + if (_buffer.isOpen()) { + _buffer.close(); + } + QIODevice::close(); +} + +qint64 QStorageDevice::size() const { return _size; } + +bool QStorageDevice::seek(qint64 pos) { + if (!_buffer.isOpen()) { + return false; + } + + return QIODevice::seek(pos); +} + +bool QStorageDevice::canReadLine() const { return false; } + +qint64 QStorageDevice::readData(char *data, qint64 maxlen) { + if (!isOpen() || !maxlen) { + return -1; + } + + if (maxlen > std::numeric_limits::max() || + (maxlen < 0 && _size > 1024 * 1024 * 1024)) { + qWarning() << "Read a lot mount of data once is not allowed"; + return -1; + } + + if (maxlen < 0) { + maxlen = _size; + } + + auto rp = std::div(this->pos(), CHUNK_SIZE); + _buffer.seek(rp.quot * CHUNK_SIZE); + + DWORD bytesRead = 0; + + if (rp.rem) { + auto buf = std::make_unique(maxlen); + _buffer.read(buf.get(), maxlen); + std::memcpy(data, buf.get() + rp.rem, maxlen); + } else { + _buffer.read(data, maxlen); + } + + return maxlen; +} + +qint64 QStorageDevice::writeData(const char *data, qint64 len) { + // qt will check writeable attr + if (!isOpen()) { + return false; + } + + // Ensure maxSize is a multiple of the sector size + auto r = std::div(len, CHUNK_SIZE); + auto alignLen = r.quot * CHUNK_SIZE; + + auto rp = std::div(this->pos(), CHUNK_SIZE); + _buffer.seek(rp.quot * CHUNK_SIZE); + if (rp.rem) { + } + + _buffer.write(data, alignLen); + + if (r.rem) { + _buffer.seek(this->pos() + alignLen); + auto buf = std::make_unique(CHUNK_SIZE); + _buffer.read(buf.get(), CHUNK_SIZE); + DWORD byteWritten_A = 0; + std::memcpy(buf.get(), data + alignLen, r.rem); + + if (_buffer.write(buf.get(), CHUNK_SIZE)) { + qWarning() << "Failed to write data to device"; + return -1; + } + } + + return len; +} + +#endif diff --git a/3rdparty/QHexView/document/qstoragedevice.h b/3rdparty/QHexView/document/qstoragedevice.h index b018833..66fe336 100644 --- a/3rdparty/QHexView/document/qstoragedevice.h +++ b/3rdparty/QHexView/document/qstoragedevice.h @@ -1,13 +1,19 @@ #ifndef QSTORAGEDEVICE_H #define QSTORAGEDEVICE_H +#include + +#ifdef Q_OS_WIN + #include #include +#include + class QStorageDevice : public QIODevice { Q_OBJECT public: - QStorageDevice(); + QStorageDevice(QObject *parent = nullptr); void setStorage(const QStorageInfo &storage); @@ -15,11 +21,24 @@ public: private: QStorageInfo _storage; + QFile _buffer; + DWORD CHUNK_SIZE; + qint64 _size; // QIODevice interface +public: + virtual bool isSequential() const override; + virtual bool open(OpenMode mode) override; + virtual void close() override; + virtual qint64 size() const override; + virtual bool seek(qint64 pos) override; + virtual bool canReadLine() const override; + protected: virtual qint64 readData(char *data, qint64 maxlen) override; virtual qint64 writeData(const char *data, qint64 len) override; }; +#endif + #endif // QSTORAGEDEVICE_H diff --git a/3rdparty/qcodeedit2/CMakeLists.txt b/3rdparty/qcodeedit2/CMakeLists.txt index 65d1247..1c268b2 100644 --- a/3rdparty/qcodeedit2/CMakeLists.txt +++ b/3rdparty/qcodeedit2/CMakeLists.txt @@ -93,7 +93,7 @@ add_library(QCodeEditor2 STATIC ${SOURCE_FILES} ${DOCUMENT_SRC} ${WIDGETS_SRC} ${QNFA_SRC} ${SNIPPET_SRC}) target_compile_definitions(QCodeEditor2 PUBLIC _QCODE_EDIT_BUILD_ - _QCODE_EDIT_EMBED_ _QCODE_MODEL_) + _QCODE_EDIT_EMBED_) target_include_directories( QCodeEditor2 @@ -106,5 +106,4 @@ target_include_directories( target_link_libraries( QCodeEditor2 PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Gui - Qt${QT_VERSION_MAJOR}::Xml Qt${QT_VERSION_MAJOR}::PrintSupport - QCodeModel2) + Qt${QT_VERSION_MAJOR}::Xml Qt${QT_VERSION_MAJOR}::PrintSupport) diff --git a/3rdparty/qcodeedit2/lib/qcodecompletionengine.cpp b/3rdparty/qcodeedit2/lib/qcodecompletionengine.cpp index ffa62b9..ea91512 100644 --- a/3rdparty/qcodeedit2/lib/qcodecompletionengine.cpp +++ b/3rdparty/qcodeedit2/lib/qcodecompletionengine.cpp @@ -26,10 +26,6 @@ #include #include -#ifdef _QCODE_MODEL_ -#include "qcodebuffer.h" -#endif - /*! */ @@ -84,11 +80,6 @@ void QCodeCompletionEngine::removeTrigger(const QString &s) { /*! -*/ -void QCodeCompletionEngine::setCodeModel(QCodeModel *m) { Q_UNUSED(m) } - -/*! - */ QEditor *QCodeCompletionEngine::editor() const { return pEdit; } @@ -253,38 +244,9 @@ bool QCodeCompletionEngine::eventFilter(QObject *o, QEvent *e) { */ void QCodeCompletionEngine::complete(const QDocumentCursor &c, const QString &trigger) { -#ifdef _QCODE_MODEL_ - // TODO : - // * use a more efficient design by avoiding deep copy of the data - // * only lex the requested part (stop at cursor or topmost frame required - // for proper class hierarchy) - - QDocumentCursor cc = c; - cc.movePosition(1, QDocumentCursor::Start, QDocumentCursor::KeepAnchor); - - // qDebug("%s", qPrintable(cc.selectedText())); - - QCodeBuffer buffer(cc.selectedText()); - // QCodeBuffer buffer(c.document()->text()); - complete(&buffer, trigger); -#else Q_UNUSED(c) Q_UNUSED(trigger) qWarning("From complete(QDocumentCursor, QString)"); qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should " "reimplement at least one of the complete() method..."); -#endif -} - -/*! - \overload - \brief Overloaded completion callback -*/ -void QCodeCompletionEngine::complete(QCodeStream *s, const QString &trigger) { - Q_UNUSED(s) - Q_UNUSED(trigger) - - qWarning("From complete(QCodeStream*, QString)"); - qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should" - "reimplement at least on of the complete() method..."); } diff --git a/3rdparty/qcodeedit2/lib/qcodecompletionengine.h b/3rdparty/qcodeedit2/lib/qcodecompletionengine.h index 3bea37a..af3ad71 100644 --- a/3rdparty/qcodeedit2/lib/qcodecompletionengine.h +++ b/3rdparty/qcodeedit2/lib/qcodecompletionengine.h @@ -57,8 +57,6 @@ public: void addTrigger(const QString &s); void removeTrigger(const QString &s); - virtual void setCodeModel(QCodeModel *m); - virtual void retranslate(); signals: @@ -74,7 +72,6 @@ protected: virtual void run(); virtual bool eventFilter(QObject *o, QEvent *e); - virtual void complete(QCodeStream *s, const QString &trigger); virtual void complete(const QDocumentCursor &c, const QString &trigger); private: diff --git a/3rdparty/qcodemodel2/CMakeLists.txt b/3rdparty/qcodemodel2/CMakeLists.txt deleted file mode 100644 index 8364fbb..0000000 --- a/3rdparty/qcodemodel2/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -cmake_minimum_required(VERSION 3.6) -project(QCodeModel2 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) - -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - -find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Gui) -find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Gui) - -add_definitions(-D_QCODE_MODEL_BUILD_STATIC_) - -add_library( - QCodeModel2 STATIC - qcm-config.h - qcodemodel.h - qcodeproxymodel.h - qcodenode.h - qcodenodepool.h - qsourcecodewatcher.h - qcodeview.h - qcodeserializer.h - qcodestream.h - qcodedevice.h - qcodebuffer.h - qcodelexer.h - qcodeparser.h - qcodeloader.h - qcodemodel.cpp - qcodeproxymodel.cpp - qcodenode.cpp - qcodenodepool.cpp - qsourcecodewatcher.cpp - qcodeview.cpp - qcodeserializer.cpp - qcodestream.cpp - qcodedevice.cpp - qcodebuffer.cpp - qcodelexer.cpp - qcodeparser.cpp - qcodeloader.cpp - resources.qrc) - -target_include_directories(QCodeModel2 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") - -target_link_libraries(QCodeModel2 PRIVATE Qt${QT_VERSION_MAJOR}::Widgets - Qt${QT_VERSION_MAJOR}::Gui) - -target_compile_definitions(QCodeModel2 PUBLIC -D_QCODE_MODEL_BUILD_STATIC_) diff --git a/3rdparty/qcodemodel2/qcodebuffer.cpp b/3rdparty/qcodemodel2/qcodebuffer.cpp deleted file mode 100644 index 69acf6c..0000000 --- a/3rdparty/qcodemodel2/qcodebuffer.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "qcodebuffer.h" - -/*! - \file qcodebuffer.cpp - \brief Implementation of the QCodebuffer class. -*/ - -#include - -/*! - \class QCodebuffer - \brief Code stream that operates on a static string buffer -*/ - -/*! - \brief Constructs a code buffer from an Unicode string - - \note The string is converted to local8Bit() -*/ -QCodeBuffer::QCodeBuffer(const QString &s) - : QCodeStream(), iPos(0), sBuffer(s.toLocal8Bit()) { - sBuffer.replace("\r\n", "\n"); - sBuffer.replace("\r", "\n"); -} - -/*! - \brief Constructs a code buffer from a byte array -*/ -QCodeBuffer::QCodeBuffer(const QByteArray &s) - : QCodeStream(), iPos(0), sBuffer(s) { - sBuffer.replace("\r\n", "\n"); - sBuffer.replace("\r", "\n"); -} - -/*! - \brief return the char pointed to by the internal pointer and update the - pointer -*/ -char QCodeBuffer::getChar() { - if (iPos < sBuffer.length()) - return sBuffer.at(iPos++); - else - return '\0'; -} - -/*! - \brief Move back by one character -*/ -void QCodeBuffer::ungetChar(char) { - if (iPos > 0) - --iPos; -} - -/*! - \return the content of the current line -*/ -QByteArray QCodeBuffer::readLine() { - char c; - QByteArray s; - - while ((c = getChar())) { - if (c == '\n') - break; - - s += c; - } - - return s; -} diff --git a/3rdparty/qcodemodel2/qcodedevice.cpp b/3rdparty/qcodemodel2/qcodedevice.cpp deleted file mode 100644 index 1080f63..0000000 --- a/3rdparty/qcodemodel2/qcodedevice.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "qcodedevice.h" - -/*! - \file qcodedevice.cpp - \brief Implementation of the QcodeDevice class. -*/ - -#include -#include -#include -#include - -QString stripped(const QString &s) { return QDir::cleanPath(s); } - -QString makeAbsolute(const QString &rel, const QString &abs) { - if (QFileInfo(rel).isAbsolute()) - return stripped(rel); - - QFileInfo info(abs); - QStringList ref, mov = QString(rel).replace("\\", "/").split("/"); - ref = (info.isFile() ? info.absolutePath() : info.absoluteFilePath()) - .replace("\\", "/") - .split("/"); - - foreach (QString s, mov) { - if (s == ".") - continue; - - if (s == "..") { - if (ref.count()) - ref.removeLast(); - } else { - ref << s; - } - } - - return stripped(ref.join("/")); -} - -/*! - \class QCodeDevice - \brief Code stream that operates on local files -*/ - -/*! - -*/ -QCodeDevice::QCodeDevice(const QString &f) : m_pos(0), m_beg(0) { - setContextFile(f); - - QFile file(f); - - if (file.open(QFile::ReadOnly | QFile::Text)) { - buffer = file.readAll(); - } else { - qWarning("Device not found : %s", qPrintable(f)); - } -} - -bool QCodeDevice::tryFetchOtherContext(const QString &f) { - m_pos = 0; - m_beg = 0; - buffer.clear(); - - QString fn = makeAbsolute(f, contextFile()); - QFile file(fn); - - if (!file.open(QFile::ReadOnly | QFile::Text)) { - qWarning("Unable to read %s", qPrintable(fn)); - return false; - } - - buffer = file.readAll(); - setContextFile(fn); - - return true; -} - -char QCodeDevice::getChar() { - return (m_pos < buffer.length()) ? buffer.at(m_pos++) : 0; -} - -void QCodeDevice::ungetChar(char) { - if (m_beg >= m_pos) - return; - - --m_pos; -} - -QByteArray QCodeDevice::readLine() { - QByteArray b = buffer.mid(buffer.indexOf('\n', m_pos) - m_pos); - - m_pos += b.length(); - return b; -} diff --git a/3rdparty/qcodemodel2/qcodedevice.h b/3rdparty/qcodemodel2/qcodedevice.h deleted file mode 100644 index 2f63005..0000000 --- a/3rdparty/qcodemodel2/qcodedevice.h +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef _QCODE_DEVICE_H_ -#define _QCODE_DEVICE_H_ - -#include "qcodestream.h" - -/*! - \file qcodedevice.h - \brief Definition of the QCodeDevice class. -*/ - -class QIODevice; - -class QCM_EXPORT QCodeDevice : public QCodeStream { -public: - QCodeDevice(const QString &f); - - virtual char getChar(); - virtual void ungetChar(char c); - - virtual QByteArray readLine(); - - virtual bool tryFetchOtherContext(const QString &f); - -private: - int m_pos, m_beg; - QByteArray buffer; -}; - -#endif // _QCODE_DEVICE_H_ diff --git a/3rdparty/qcodemodel2/qcodelexer.cpp b/3rdparty/qcodemodel2/qcodelexer.cpp deleted file mode 100644 index a4b2f90..0000000 --- a/3rdparty/qcodemodel2/qcodelexer.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "qcodelexer.h" - -/*! - \file qcodelexer.cpp - \brief Implementation of the QCodeLexer class. -*/ - -#include "qcodestream.h" - -/*! - \class QCodeLexer - \brief Base class for code lexers -*/ - -QCodeLexer::QCodeLexer() {} - -QCodeLexer::QCodeLexer(QCodeStream *s) : input(s) {} - -QCodeLexer::~QCodeLexer() {} - -void QCodeLexer::setInput(QCodeStream *s, LexMode m) { - Q_UNUSED(m) - - input = s; -} - -QString QCodeLexer::contextFile() const { - return input ? input->contextFile() : QString(); -} diff --git a/3rdparty/qcodemodel2/qcodelexer.h b/3rdparty/qcodemodel2/qcodelexer.h deleted file mode 100644 index 6891b0c..0000000 --- a/3rdparty/qcodemodel2/qcodelexer.h +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef _QCODE_LEXER_H_ -#define _QCODE_LEXER_H_ - -#include "qcm-config.h" - -/*! - \file qcodelexer.h - \brief Definition of the QCodeLexer class. -*/ - -#include -#include - -class QCodeStream; - -class QCM_EXPORT QCodeLexer { -public: - enum LexMode { Normal, KeepLineSeparators }; - - QCodeLexer(); - QCodeLexer(QCodeStream *s); - virtual ~QCodeLexer(); - - virtual void setInput(QCodeStream *s, LexMode m = Normal); - - virtual QToken nextToken() = 0; - virtual QToken previousToken() = 0; - - virtual QTokenList tokens() = 0; - - virtual int lineForToken(int tokenId, int minLine = 0) const = 0; - - QString contextFile() const; - -protected: - QCodeStream *input; -}; - -#endif // _QCODE_LEXER_H_ diff --git a/3rdparty/qcodemodel2/qcodeloader.cpp b/3rdparty/qcodemodel2/qcodeloader.cpp deleted file mode 100644 index 308a36e..0000000 --- a/3rdparty/qcodemodel2/qcodeloader.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "qcodeloader.h" - -/*! - \file qcodeloader.cpp - \brief Implementation of the QCodeLoader class. -*/ - -#include "qcodemodel.h" -#include "qcodenode.h" -#include "qcodeparser.h" - -#include -#include -#include - -/*! - \class QCodeLoader - \brief A parsers management class - - QCodeLoader owns a collection of QCodeParser object - and request them to generate project trees from files. -*/ - -/*! - \brief ctor -*/ -QCodeLoader::QCodeLoader(QObject *p) : QThread(p) {} - -/*! - \brief dtor -*/ -QCodeLoader::~QCodeLoader() { - // qDeleteAll(m_parsers); -} - -/*! - \brief Add a parser to the collection - - \warning The parser is not taken over. It won't get deleted - from QCodeLoader dtor. -*/ -void QCodeLoader::addParser(QCodeParser *p) { - if (!m_parsers.contains(p)) - m_parsers << p; -} - -/*! - \brief Remove a parser from the collection - - \warning The parser is NOT deleted. -*/ -void QCodeLoader::removeParser(QCodeParser *p) { m_parsers.removeAll(p); } - -/*! - \brief Update the content of a given node to -*/ -void QCodeLoader::update(QCodeNode *group, const QString &file) { - if (!group) - return; - - if (!QFile::exists(file)) { - QStack l; - - l.push(group); - - while (l.count()) { - QCodeNode *n = l.pop(); - - if (n->context() == file) { - QCodeNode *p = n->parent; - - n->detach(); - delete n; - - while (p && p->children.isEmpty() && (p != group)) { - n = p; - p = p->parent; - - n->detach(); - delete n; - } - } else { - foreach (QCodeNode *c, n->children) - l.push(c); - } - } - - return; - } - - // qDebug("update(%s, %s)", group->role(QCodeNode::Name).constData(), - // qPrintable(file)); - - foreach (QCodeParser *p, m_parsers) { - if (!p->canParse(file)) - continue; - - QCodeNode *ln = 0; - QByteArray roles("l@"); - roles += p->language().toLocal8Bit(); - - foreach (QCodeNode *c, group->children) { - if (c->roles == roles) { - ln = c; - break; - } - } - - if (!ln) { - ln = p->getNode(); - ln->roles = roles; - ln->attach(group); - } - - p->update(ln, file); - break; - } -} - -/*! - \brief Attempt to open load class hierarchy from a set of files - \return true on success - \param group Name of the toplevel group which will get created on - success \param files Files to load \param dest Destination model -*/ -bool QCodeLoader::load(const QString &group, QStringList files, - QCodeModel *dest) { - // qDebug("load(%s, (%s), %p)", qPrintable(group), qPrintable(files.join(", - // ")), dest); - bool done = false; - - QCodeNode *g = new QCodeNode; - g->roles = QByteArray("g@") + QFileInfo(group).fileName().toLocal8Bit() + - "@" + group.toLocal8Bit(); - dest->appendTopLevelNode(g); - - foreach (QCodeParser *p, m_parsers) { - QStringList lf; - - foreach (QString fn, files) - if (p->canParse(fn)) - lf << fn; - - if (lf.isEmpty()) - continue; - - done = true; - break; - } - - if (!done) - return false; - - OpenRequest r; - r.files = files; - r.group = group; - r.model = dest; - - m_request.enqueue(r); - - if (!isRunning()) - QTimer::singleShot(0, this, SLOT(start())); - - return true; -} - -/*! - \internal -*/ -void QCodeLoader::run() { - QTimer::singleShot(0, this, SLOT(process())); - - exec(); - - // process(); -} - -/*! - \internal -*/ -void QCodeLoader::process() { - while (m_request.count()) { - OpenRequest r = m_request.dequeue(); - - bool done = false; - - QCodeNode *g; - QList gl = r.model->topLevelNodes(); - - foreach (g, gl) { - if (g->role(QCodeNode::Context) != r.group) - continue; - - foreach (QCodeParser *p, m_parsers) { - QStringList lf; - - foreach (QString fn, r.files) - if (p->canParse(fn)) - lf << fn; - - if (lf.isEmpty()) - continue; - - done = true; - - QCodeNode *ln = p->getNode(); - ln->roles = QByteArray("l@") + p->language().toLocal8Bit(); - - foreach (QString fn, lf) { - r.files.removeAll(fn); - - p->update(ln, fn); - } - - ln->attach(g); - } - - break; - } - } - - quit(); -} diff --git a/3rdparty/qcodemodel2/qcodeloader.h b/3rdparty/qcodemodel2/qcodeloader.h deleted file mode 100644 index 56a5ed9..0000000 --- a/3rdparty/qcodemodel2/qcodeloader.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef _QCODE_LOADER_H_ -#define _QCODE_LOADER_H_ - -#include "qcm-config.h" - -/*! - \file qcodeloader.h - \brief Definition of the QCodeLoader class. -*/ - -#include -#include -#include -#include - -struct QCodeNode; -class QCodeModel; -class QCodeParser; - -class QCM_EXPORT QCodeLoader : public QThread { - Q_OBJECT - -public: - QCodeLoader(QObject *p = nullptr); - virtual ~QCodeLoader(); - -public slots: - void update(QCodeNode *group, const QString &file); - bool load(const QString &group, QStringList files, QCodeModel *dest); - - void addParser(QCodeParser *p); - void removeParser(QCodeParser *p); - -protected: - virtual void run(); - -protected slots: - virtual void process(); - -private: - struct OpenRequest { - QString group; - QStringList files; - QCodeModel *model; - }; - - QQueue m_request; - QList m_parsers; -}; - -#endif // !_QCODE_LOADER_H_ diff --git a/3rdparty/qcodemodel2/qcodeparser.cpp b/3rdparty/qcodemodel2/qcodeparser.cpp deleted file mode 100644 index a755da5..0000000 --- a/3rdparty/qcodemodel2/qcodeparser.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2006-2009 fullmetalcoder - ** - ** This file is part of the Edyuk project - ** - ** This file may be used under the terms of the GNU General Public License - ** version 3 as published by the Free Software Foundation and appearing in the - ** file GPL.txt included in the packaging of this file. - ** - ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - ** - ****************************************************************************/ - -#include "qcodeparser.h" - -/*! - \file qcodeparser.cpp - \brief Implementation of the QCodeParser class. -*/ - -#include "qcodedevice.h" -#include "qcodelexer.h" -#include "qcodemodel.h" -#include "qcodenode.h" -#include "qcodenodepool.h" -#include "qcodestream.h" - -#include "qsourcecodewatcher.h" - -#include -#include -#include -#include - -/*! - \class QCodeParser - \brief Base class for code parsers - - \see QCodeLexer - \see QCodeLoader -*/ - -/*! - \brief ctor -*/ -QCodeParser::QCodeParser() : m_pool(0) {} - -/*! - \brief dtor -*/ -QCodeParser::~QCodeParser() {} - -/*! - \return The node pool to which this parser has access -*/ -QCodeNodePool *QCodeParser::nodePool() const { return m_pool; } - -/*! - \brief Set the node pool from which the parser should - allocate its node (a null pointer causes heap allocation - to be used all the time.) -*/ -void QCodeParser::setNodePool(QCodeNodePool *p) { m_pool = p; } - -/*! - \return A valid QCodeNode object - If the parser has access to a nodePool(), it allocates - the new node from it, otherwise it allocates it on heap. -*/ -QCodeNode *QCodeParser::getNode() { - return m_pool ? m_pool->alloc() : new QCodeNode; -} - -/*! - \brief Parse a single file and construct code tree - \param f file to parse - \return The group node (named after the file) containing parsing result -*/ -QCodeNode *QCodeParser::parse(const QString &f) { - if (!QFile::exists(f) || !QFileInfo(f).isReadable()) - return 0; - - QCodeDevice stream(f); - QCodeNode *node = getNode(); - QCodeLexer *lex = lexer(&stream); - - node->roles = QByteArray("g@") + f.toLocal8Bit() + "@" + f.toLocal8Bit(); - - update(node, lex); - - delete lex; - - return node; -} - -/*! - \brief Update the content of a node according to the content of a file - \param n node to update (most probably a group...) - \param file file from which to extract code hierarchy -*/ -void QCodeParser::update(QCodeNode *n, const QString &file) { - if (!QFile::exists(file) || !QFileInfo(file).isReadable()) { - QStack l; - - l.push(n); - - while (l.count()) { - QCodeNode *tn = l.pop(); - - if (tn->context() == file) { - QCodeNode *p = tn->parent; - - tn->detach(); - delete tn; - - while (p && p->children.isEmpty() && - (p->type() != QCodeNode::Group)) { - tn = p; - p = p->parent; - - tn->detach(); - delete tn; - } - } else { - foreach (QCodeNode *c, tn->children) - l.push(c); - } - } - - return; - } - - // qDebug("updating %s in %s", qPrintable(file), - // n->role(QCodeNode::Name).constData()); - - QCodeDevice stream(file); - - QSourceCodeWatcher *w = QSourceCodeWatcher::watcher(n, this); - - if (w && !w->files().contains(file)) - w->addPath(file); - - QCodeLexer *lex = lexer(&stream); - - update(n, lex); - - delete lex; -} diff --git a/3rdparty/qcodemodel2/qcodeparser.h b/3rdparty/qcodemodel2/qcodeparser.h deleted file mode 100644 index ac94432..0000000 --- a/3rdparty/qcodemodel2/qcodeparser.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef _QCODE_PARSER_H_ -#define _QCODE_PARSER_H_ - -#include "qcm-config.h" - -#include - -struct QCodeNode; -class QCodeModel; -class QCodeLexer; -class QCodeStream; -class QCodeNodePool; - -class QCM_EXPORT QCodeParser { - friend class QCodeLoader; - -public: - QCodeParser(); - virtual ~QCodeParser(); - - virtual QString language() const = 0; - virtual bool canParse(const QString &fn) const = 0; - - QCodeNodePool *nodePool() const; - void setNodePool(QCodeNodePool *p); - - QCodeNode *parse(const QString &f); - - virtual QCodeLexer *lexer(QCodeStream *s) = 0; - - virtual void update(QCodeNode *n, const QString &file); - virtual void update(QCodeNode *n, QCodeLexer *l, bool check = true) = 0; - -protected: - QCodeNode *getNode(); - -private: - QCodeNodePool *m_pool; -}; - -#endif // !_QCODE_PARSER_H_ diff --git a/3rdparty/qcodemodel2/qcodeproxymodel.h b/3rdparty/qcodemodel2/qcodeproxymodel.h deleted file mode 100644 index 151118c..0000000 --- a/3rdparty/qcodemodel2/qcodeproxymodel.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2006-2009 fullmetalcoder - ** - ** This file is part of the Edyuk project - ** - ** This file may be used under the terms of the GNU General Public License - ** version 3 as published by the Free Software Foundation and appearing in the - ** file GPL.txt included in the packaging of this file. - ** - ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - ** - ****************************************************************************/ - -#ifndef _QCODE_PROXY_MODEL_H_ -#define _QCODE_PROXY_MODEL_H_ - -#include "qcm-config.h" - -/*! - \file qcodeproxymodel.h - \brief Definition of the QCodeProxyModel class. -*/ - -#include - -class QCM_EXPORT QCodeProxyModel : public QSortFilterProxyModel { - Q_OBJECT - -public: - QCodeProxyModel(QObject *p = nullptr); - virtual ~QCodeProxyModel(); - -protected: - virtual bool lessThan(const QModelIndex &left, - const QModelIndex &right) const; -}; - -#endif // !_QCODE_PROXY_MODEL_H_ diff --git a/3rdparty/qcodemodel2/qcodestream.cpp b/3rdparty/qcodemodel2/qcodestream.cpp deleted file mode 100644 index 46e8e30..0000000 --- a/3rdparty/qcodemodel2/qcodestream.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "qcodestream.h" - -/*! - \file qcodestream.cpp - \brief Implementation of the QCodeStream class. -*/ - -/*! - \class QCodeStream - \brief Base class for code input streams -*/ - -QString QCodeStream::contextFile() const { - // qDebug(" <= context query : %s", qPrintable(sContext)); - return sContext; -} - -void QCodeStream::setContextFile(const QString &f) { - // qDebug(" => context switch : %s", qPrintable(f)); - sContext = f; -} - -bool QCodeStream::tryFetchOtherContext(const QString &) { return false; } diff --git a/3rdparty/qcodemodel2/qcodestream.h b/3rdparty/qcodemodel2/qcodestream.h deleted file mode 100644 index d287251..0000000 --- a/3rdparty/qcodemodel2/qcodestream.h +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2006-2009 fullmetalcoder -** -** This file is part of the Edyuk project -** -** This file may be used under the terms of the GNU General Public License -** version 3 as published by the Free Software Foundation and appearing in the -** file GPL.txt included in the packaging of this file. -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef _QCODE_STREAM_H_ -#define _QCODE_STREAM_H_ - -#include "qcm-config.h" - -/*! - \file qcodestream.h - \brief Definition of the QCodeStream class. -*/ - -#include - -class QByteArray; - -class QCM_EXPORT QCodeStream { -public: - virtual ~QCodeStream() {} - - virtual char getChar() = 0; - virtual void ungetChar(char c) = 0; - - virtual QByteArray readLine() = 0; - - virtual QString contextFile() const; - virtual void setContextFile(const QString &f); - - virtual bool tryFetchOtherContext(const QString &f); - -private: - QString sContext; -}; - -#endif // !_QCODE_STREAM_H_ diff --git a/3rdparty/qcodemodel2/resources.qrc b/3rdparty/qcodemodel2/resources.qrc deleted file mode 100644 index c2db8c7..0000000 --- a/3rdparty/qcodemodel2/resources.qrc +++ /dev/null @@ -1,20 +0,0 @@ - - - completion/CVclass.png - completion/CVenum.png - completion/CVenumerator.png - completion/CVglobal_meth.png - completion/CVglobal_var.png - completion/CVnamespace.png - completion/CVpackage_meth.png - completion/CVpackage_var.png - completion/CVprivate_meth.png - completion/CVprivate_var.png - completion/CVprotected_meth.png - completion/CVprotected_var.png - completion/CVpublic_meth.png - completion/CVpublic_var.png - completion/CVtypedef.png - completion/classnew.png - - diff --git a/3rdparty/qwindowkit b/3rdparty/qwindowkit index f93657f..ae0cbbc 160000 --- a/3rdparty/qwindowkit +++ b/3rdparty/qwindowkit @@ -1 +1 @@ -Subproject commit f93657fa82bdd37dba68ea962d5e9b2cf4fd4d60 +Subproject commit ae0cbbcad47ac5613358354d89176ea9574bed99 diff --git a/CMakeLists.txt b/CMakeLists.txt index 84e297c..8ea0a42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,6 @@ option(BUILD_STATIC "Build the static library" TRUE) add_subdirectory(3rdparty/QHexView) add_subdirectory(3rdparty/qcodeedit2) -add_subdirectory(3rdparty/qcodemodel2) add_subdirectory(3rdparty/Qt-Advanced-Docking-System) add_subdirectory(3rdparty/AngelScript/sdk/angelscript/projects/cmake) add_subdirectory(3rdparty/QConsoleWidget) @@ -179,7 +178,6 @@ set(CLASS_SRC src/class/skinmanager.h src/class/workspacemanager.cpp src/class/workspacemanager.h - src/class/setting.h src/class/eventfilter.h src/class/qkeysequences.h src/class/qkeysequences.cpp @@ -218,8 +216,6 @@ set(CLASS_SRC src/class/ascompletion.h src/class/asbuilder.h src/class/asbuilder.cpp - src/class/qaslexer.cpp - src/class/qaslexer.h src/class/qasparser.cpp src/class/qasparser.h src/class/qdocumentsearch.cpp @@ -304,10 +300,25 @@ set(CODEEDIT_WIDGET src/qcodeeditwidget/qformatconfig.cpp src/qcodeeditwidget/qformatconfig.ui) -set(PLUGIN_SRC - src/plugin/iwingplugin.h src/plugin/pluginsystem.cpp - src/plugin/pluginsystem.h src/plugin/settingpage.h - src/plugin/settingpage.cpp) +set(CODE_MODEL + src/codemodel/qcm-config.h + src/codemodel/qcodemodel.cpp + src/codemodel/qcodemodel.h + src/codemodel/qcodenode.cpp + src/codemodel/qcodenode.h + src/codemodel/qcodenodepool.cpp + src/codemodel/qcodenodepool.h + src/codemodel/qcodeproxymodel.cpp + src/codemodel/qcodeproxymodel.h + src/codemodel/qcodeserializer.cpp + src/codemodel/qcodeserializer.h + src/codemodel/qcodeview.cpp + src/codemodel/qcodeview.h + src/codemodel/qsourcecodewatcher.cpp + src/codemodel/qsourcecodewatcher.h) + +set(PLUGIN_SRC src/plugin/iwingplugin.h src/plugin/pluginsystem.cpp + src/plugin/pluginsystem.h src/plugin/settingpage.h) # localization support file( @@ -400,6 +411,7 @@ set(PROJECT_SOURCES src/dbghelper.h ${QPATHEDIT_SRC} ${WIDGET_FRAME_SRC} + ${CODE_MODEL} ${RIBBON_SRC} ${CLASS_SRC} ${MODEL_SRC} @@ -459,7 +471,6 @@ if(WINGHEX_USE_FRAMELESS) QWKWidgets QHexView QCodeEditor2 - QCodeModel2 QJsonModel angelscript QConsoleWidget @@ -476,7 +487,6 @@ else() SingleApplication::SingleApplication QHexView QCodeEditor2 - QCodeModel2 QJsonModel angelscript QConsoleWidget diff --git a/images/completion/CTvirtuals.png b/images/completion/CTvirtuals.png new file mode 100644 index 0000000..1ebc2fe Binary files /dev/null and b/images/completion/CTvirtuals.png differ diff --git a/3rdparty/qcodemodel2/completion/CVclass.png b/images/completion/CVclass.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVclass.png rename to images/completion/CVclass.png diff --git a/3rdparty/qcodemodel2/completion/CVenum.png b/images/completion/CVenum.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVenum.png rename to images/completion/CVenum.png diff --git a/3rdparty/qcodemodel2/completion/CVenumerator.png b/images/completion/CVenumerator.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVenumerator.png rename to images/completion/CVenumerator.png diff --git a/3rdparty/qcodemodel2/completion/CVglobal_meth.png b/images/completion/CVglobal_meth.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVglobal_meth.png rename to images/completion/CVglobal_meth.png diff --git a/3rdparty/qcodemodel2/completion/CVglobal_var.png b/images/completion/CVglobal_var.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVglobal_var.png rename to images/completion/CVglobal_var.png diff --git a/3rdparty/qcodemodel2/completion/CVnamespace.png b/images/completion/CVnamespace.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVnamespace.png rename to images/completion/CVnamespace.png diff --git a/3rdparty/qcodemodel2/completion/CVpackage_meth.png b/images/completion/CVpackage_meth.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVpackage_meth.png rename to images/completion/CVpackage_meth.png diff --git a/3rdparty/qcodemodel2/completion/CVpackage_var.png b/images/completion/CVpackage_var.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVpackage_var.png rename to images/completion/CVpackage_var.png diff --git a/3rdparty/qcodemodel2/completion/CVprivate_meth.png b/images/completion/CVprivate_meth.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVprivate_meth.png rename to images/completion/CVprivate_meth.png diff --git a/images/completion/CVprivate_signal.png b/images/completion/CVprivate_signal.png new file mode 100644 index 0000000..114a714 Binary files /dev/null and b/images/completion/CVprivate_signal.png differ diff --git a/images/completion/CVprivate_slot.png b/images/completion/CVprivate_slot.png new file mode 100644 index 0000000..e9b8ecd Binary files /dev/null and b/images/completion/CVprivate_slot.png differ diff --git a/3rdparty/qcodemodel2/completion/CVprivate_var.png b/images/completion/CVprivate_var.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVprivate_var.png rename to images/completion/CVprivate_var.png diff --git a/3rdparty/qcodemodel2/completion/CVprotected_meth.png b/images/completion/CVprotected_meth.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVprotected_meth.png rename to images/completion/CVprotected_meth.png diff --git a/images/completion/CVprotected_signal.png b/images/completion/CVprotected_signal.png new file mode 100644 index 0000000..07aef0b Binary files /dev/null and b/images/completion/CVprotected_signal.png differ diff --git a/images/completion/CVprotected_slot.png b/images/completion/CVprotected_slot.png new file mode 100644 index 0000000..db08489 Binary files /dev/null and b/images/completion/CVprotected_slot.png differ diff --git a/3rdparty/qcodemodel2/completion/CVprotected_var.png b/images/completion/CVprotected_var.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVprotected_var.png rename to images/completion/CVprotected_var.png diff --git a/3rdparty/qcodemodel2/completion/CVpublic_meth.png b/images/completion/CVpublic_meth.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVpublic_meth.png rename to images/completion/CVpublic_meth.png diff --git a/images/completion/CVpublic_signal.png b/images/completion/CVpublic_signal.png new file mode 100644 index 0000000..5a10185 Binary files /dev/null and b/images/completion/CVpublic_signal.png differ diff --git a/images/completion/CVpublic_slot.png b/images/completion/CVpublic_slot.png new file mode 100644 index 0000000..b04b49d Binary files /dev/null and b/images/completion/CVpublic_slot.png differ diff --git a/3rdparty/qcodemodel2/completion/CVpublic_var.png b/images/completion/CVpublic_var.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVpublic_var.png rename to images/completion/CVpublic_var.png diff --git a/images/completion/CVstruct.png b/images/completion/CVstruct.png new file mode 100644 index 0000000..ec953ad Binary files /dev/null and b/images/completion/CVstruct.png differ diff --git a/3rdparty/qcodemodel2/completion/CVtypedef.png b/images/completion/CVtypedef.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/CVtypedef.png rename to images/completion/CVtypedef.png diff --git a/images/completion/CVunion.png b/images/completion/CVunion.png new file mode 100644 index 0000000..aa2d117 Binary files /dev/null and b/images/completion/CVunion.png differ diff --git a/3rdparty/qcodemodel2/completion/classnew.png b/images/completion/classnew.png similarity index 100% rename from 3rdparty/qcodemodel2/completion/classnew.png rename to images/completion/classnew.png diff --git a/lang/zh_CN/winghex.ts b/lang/zh_CN/winghex.ts index 22d3b56..2a46753 100644 --- a/lang/zh_CN/winghex.ts +++ b/lang/zh_CN/winghex.ts @@ -502,7 +502,7 @@ GeneralSettingDialog - + General 基本 @@ -616,7 +616,7 @@ LanguageManager - + Chinese(Simplified) 中文(简体) @@ -766,8 +766,8 @@ - - + + CopyToClipBoard 数据已拷贝到粘贴板 @@ -807,8 +807,8 @@ - - + + BookMark 书签 @@ -990,7 +990,7 @@ - + Fill 填充 @@ -1249,120 +1249,120 @@ 关于 QT - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重复 ID (%2),该 ID 已被插件 %3 注册 - - + + ChooseFile 选择文件 - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + Error 错误 - - - - + + + + FileNotExist 文件不存在! - - - - - + + + + + FilePermission 因文件权限无法继续! - + ProjectFile (*.wingpro) 项目文件 (*.wingpro) - + Root Required! 需要管理员权限继续操作! - + ReloadSuccessfully 文件重新加载成功! - + ReloadUnSuccessfully 文件重新加载失败! - - - + + + ChooseSaveFile 请选择保存文件路径: - + NoMoreClone 克隆已到上限,无法继续操作! - + FindFininishBusy 查找任务繁忙,请勿重复查找! - + MayTooMuchFindResult 搜索数量已到达上限,结果可能不全,建议请按区段搜索。 - + ConfirmSave 正在关闭未保存的文件或工作区,你确定保存吗? - + ConfirmAPPSave 你尝试关闭程序,但仍存在未保存的文件或工作区,你确定保存这些更改吗? - - + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作区错误! - - - + + + Warn 警告 @@ -1372,163 +1372,163 @@ 脚本对象 - - - + + + SourceChanged 局部打开原始文件更改! - - + + SaveSourceFileError 由于原文件更改,保存文件失败! - + SaveUnSuccessfully 保存失败! - + ChooseExportFile 请选择导出文件路径: - + ExportSuccessfully 导出成功! - + ExportSourceFileError 由于原文件更改,导出文件失败! - + ExportUnSuccessfully 导出失败! - + SaveSelSuccess 保存选区字节成功! - + SaveSelError 保存选区字节失败,因文件不具有可写权限! - - + + CutToClipBoard 数据已剪切到粘贴板! - - + + UnCutToClipBoard 由于保持大小限制,数据剪切到粘贴板失败! - - + + UnCopyToClipBoard 由于保持大小限制,数据剪切到复制板失败! - + FindFininish 查找结果完毕! - + PleaseInputFill 请输入填充字节值 - + FillInputError 填充字节输入错误 - - - - - - - - + + + + + + + + CheckKeepSize 请检查锁定文件大小是否开启! - - + + InputComment 请输入批注: - - - + + + NoSelection 没有选区,无法继续的操作! - + NoMetaData 无可编辑标记 - + EmptyFindResult 没有可导出的搜索结果! - + SaveFindResult 导出搜索结果成功! - + SaveFindResultError 导出结果失败! - + TooManyBytesDecode 超出解码字节限制…… - + ExportLogError 导出日志失败! - + ExportLogSuccess 导出日志成功,路径: - + ClearLogSuccess 清空日志成功! - + Too much opened files 打开的文件过多,无法继续操作! - + CopyLimit 拷贝字节超出限制 - + ErrOpenFileBelow 打开文件出现错误(由于权限不足),如下为打开错误的文件: @@ -1658,7 +1658,7 @@ 级别 - + Others 杂项 @@ -1691,27 +1691,27 @@ 插件: - + Plugin 插件 - + pluginName 插件名 - + pluginAuthor 插件作者 - + pluginVersion 插件版本 - + pluginComment 插件说明 @@ -1815,8 +1815,8 @@ QCodeCompletionEngine - - + + &Trigger completion 触发填充(&T) @@ -4207,37 +4207,37 @@ Do you want them to be saved? ScriptSettingDialog - + Script 脚本 - + RawName: 源名称: - + Name: 名称: - + Author: 作者: - + License: 协议: - + HomePage: 主页: - + Comment: 说明: @@ -4293,375 +4293,375 @@ Do you want them to be saved? ScriptingDialog - + ScriptEditor 脚本编辑器 - + ScriptPermissionDenied 因权限无法打开脚本 - + File 文件 - + Edit 编辑 - + Debugger 调试器 - + About 关于 - + Basic 基础 - + New 新建 - + OpenF 打开文件 - + RecentFiles 最近打开 - + Reload 重新加载 - - + + Save 保存 - + SaveAs 另存为 - + General 基本 - + Undo 撤销 - + Redo 恢复 - + Cut 剪切 - + Copy 复制 - + Paste 粘贴 - + Delete 删除 - + Lookup 查询 - + Find 查找 - + Replace 替换 - + Goto 跳转 - + Display 显示 - + Scale 缩放 - + ResetScale 重置缩放 - + Window 窗体 - - + + Editor 编辑器 - + Tools 工具 - + Layout 布局 - + Fullscreen 全屏 - + RestoreLayout 恢复默认布局 - + BreakPoint 断点 - + ToggleBreakPoint 切换断点 - + AddBreakPoint 添加断点 - + Settings 设置 - + Local 本地 - + Global 全局 - + Variables 变量 - + BreakPoints 断点 - + ConsoleOutput 输出 - + StackTrace 栈跟踪 - + Watch 监视 - - - - - - + + + + + + Error 错误 - + Too much opened files 打开的文件过多,无法继续操作! - - + + ChooseFile 选择文件 - - - + + + FilePermission 因文件权限无法继续! - + ReloadSuccessfully 文件重新加载成功! - + ReloadUnSuccessfully 文件重新加载失败! - + ChooseSaveFile 请选择保存文件路径: - - + + SaveSuccessfully 保存成功! - + SaveUnSuccessfully 保存失败! - - + + CannotSave2RunScript 无法保存,故无法继续运行脚本。 - - + + ScriptStillRunning 脚本仍在运行,你确定要退出吗? - + View 视图 - + Debug 调试 - + Run 运行 - + RunWithDbg 调试运行 - + Pause 暂停 - + Continue 继续 - + Stop 停止 - + Restart 重启 - + StepInto 单步步入 - + StepOver 单步步过 - + StepOut 单步跳出 - + RemoveBreakPoint 删除断点 - + Info 信息 - + Software 软件 - + Sponsor 赞助 - + Wiki 网页 Wiki - + AboutQT 关于 QT @@ -4674,7 +4674,12 @@ Do you want them to be saved? 设置 - + + TakeEffectRestart + 该选项重启软件生效 + + + This will reset all settings. Are you sure to continue? 这将会重置所有设置。你确认继续吗? @@ -4963,7 +4968,7 @@ Do you want them to be saved? asDebugger - + {no engine} {无引擎} diff --git a/src/class/appmanager.cpp b/src/class/appmanager.cpp index d8c0e75..251316c 100644 --- a/src/class/appmanager.cpp +++ b/src/class/appmanager.cpp @@ -36,17 +36,6 @@ AppManager::AppManager(int &argc, char *argv[]) QFont font(set.appFontFamily(), set.appfontSize()); setFont(font); - connect(&set, &SettingManager::sigAppFontFamilyChanged, this, - [](const QString &fontfam) { - QFont font(fontfam); - setFont(font); - }); - connect(&set, &SettingManager::sigAppfontSizeChanged, this, [](int v) { - auto font = qApp->font(); - font.setPointSize(v); - qApp->setFont(font); - }); - SkinManager::instance(); LanguageManager::instance(); diff --git a/src/class/ascompletion.cpp b/src/class/ascompletion.cpp index 0920266..728154a 100644 --- a/src/class/ascompletion.cpp +++ b/src/class/ascompletion.cpp @@ -1,15 +1,9 @@ #include "ascompletion.h" -#include "class/qaslexer.h" -#include "class/qasparser.h" #include "qcalltip.h" #include "qdocumentcursor.h" #include "qdocumentline.h" -#include "qcodemodel.h" -#include "qcodenode.h" -#include "qcodeserializer.h" - // #include "plugin.h" #include @@ -115,105 +109,7 @@ static void blockRemove(QByteArray &b, char in, char out) { } } -static QList split(const QByteArray &b, const char *str, char in, - char out) { - qsizetype i = 0, last = 0; - QList l; - const auto length = qsizetype(qstrlen(str)); - - while (i < b.length()) { - if (b.at(i) == in) { - int count = 0; - - do { - if (b.at(i) == in) - ++count; - else if (b.at(i) == out) - --count; - - ++i; - - } while (count && (i < b.length())); - - } else if (!qstrncmp(b.constData() + i, str, length)) { - l << QByteArray(b.constData() + last, i - last); - i += length; - last = i; - } else { - ++i; - } - } - - if (i > last) - l << QByteArray(b.constData() + last, i - last); - - // qDebug("split \"%s\" at \"%s\" => %s", b.constData(), str, - // QModel::join(l, ",").constData()); - - return l; -} - -Q_DECL_UNUSED static QList split(const QByteArray &b, - const char *str) { - QList l; - auto length = qsizetype(qstrlen(str)); - qsizetype i = 0, last = 0; - - while (i < b.length()) { - if (!qstrncmp(b.constData() + i, str, length)) { - l << QByteArray(b.constData() + last, i - last); - i += length; - last = i; - } else { - ++i; - } - } - - if (i > last) - l << QByteArray(b.constData() + last, i - last); - - // qDebug("split \"%s\" at \"%s\" => %s", b.constData(), str, - // QModel::join(l, ",").constData()); - - return l; -} - -/* -static int contextBound(const QToken& unscoped, const QTokenList& context) -{ - int i = 0, max = context.length(); - QTokenList l = split(unscoped, "::", '<', '>'); - - while ( (max > 0) && (i < l.length()) ) - { - if ( context.at(max - 1) == l.at(i) ) - { - --max; - ++i; - } else { - break; - } - } - -// qDebug() << "max scoping between " << l << " and " << context << " is " -<< max; - - return max; -} -*/ - -extern QByteArray join(const QList &l, QByteArray glue, - int max = -1); - -QCodeCompletionBackend *AsCompletion::pBackend = nullptr; -unsigned long AsCompletion::instances = 0; - -AsCompletion::AsCompletion(QObject *p) - : QCodeCompletionEngine(p), pPopup(nullptr), pModel(nullptr) { - if (!pBackend) - pBackend = new QCodeCompletionBackend; - - ++instances; +AsCompletion::AsCompletion(QObject *p) : QCodeCompletionEngine(p) { addTrigger("."); addTrigger("->"); @@ -225,35 +121,10 @@ AsCompletion::AsCompletion(QObject *p) // EDYUK_SHORTCUT(triggerAction(), "C++ completion", tr("Ctrl+Space")); } -AsCompletion::AsCompletion(QCodeModel *m, QObject *p) - : QCodeCompletionEngine(p), pPopup(nullptr), pModel(m) { - if (!pBackend) - pBackend = new QCodeCompletionBackend; - - ++instances; - - addTrigger("."); - addTrigger("->"); - addTrigger("::"); - - // unleash the power of call tips - addTrigger("("); - - // EDYUK_SHORTCUT(triggerAction(), "C++ completion", tr("Ctrl+Space")); -} - -AsCompletion::~AsCompletion() { - --instances; - // qDebug("AsCompletion : %i remaining", instances); - - if (!instances && pBackend) { - delete pBackend; - pBackend = nullptr; - } -} +AsCompletion::~AsCompletion() {} QCodeCompletionEngine *AsCompletion::clone() { - AsCompletion *e = new AsCompletion(pModel); + AsCompletion *e = new AsCompletion(); for (auto &t : triggers()) e->addTrigger(t); @@ -274,1947 +145,4 @@ QStringList AsCompletion::extensions() const { return l; } -void AsCompletion::setCodeModel(QCodeModel *m) { pModel = m; } - -void AsCompletion::init() { - if (pBackend) - pBackend->init(); -} - -extern bool isReserved(const QToken &tok); -extern bool maybeIdentifier(const QToken &tok); -extern bool isIdentifier(const QToken &tok); - -template -static bool matchBackward(Iterator &i, QToken open, QToken close, - const Iterator &beg) { - int nest = 1; - - while (nest && --i >= beg) { - if (*i == open) - ++nest; - else if (*i == close) - --nest; - } - - return !nest; -} - -template -static bool matchForward(Iterator &i, QToken open, QToken close, - const Iterator &end) { - int nest = 1; - - while (nest && ++i < end) { - if (*i == open) - ++nest; - else if (*i == close) - --nest; - } - - return !nest; -} - -static void flush(QTokenList::const_iterator beg, - QTokenList::const_iterator end, - QHash &variables, - QTokenList stops = QTokenList() << ";") { - QToken type; - int tpl_nest = 0; - bool stillType = true; - QTokenList::const_iterator i = beg; - - // qDebug("%i{", end - beg); - - if (!maybeIdentifier(*i)) - return; - - while (i < end) { - // qDebug("%s", i->constData()); - if (stillType) { - if (*i == "(" || *i == "[" || *i == "{") - break; - - if (type.length()) - type += ' '; - - type += *i; - } else if (isIdentifier(*i)) { - if (maybeIdentifier(*(i + 1))) - break; - -#ifdef TRACE_COMPLETION - qDebug("\t{%s, %s}", i->constData(), type.constData()); -#endif - - variables[*i] = type; - } else if (stops.contains(*i)) { - break; - } else if (*i == "=") { - while ((i < end) && (*i != ",")) { - if (*i == "<") - matchForward(i, "<", ">", end); - else if (*i == "(") - matchForward(i, "(", ")", end); - else if (*i == "[") - matchForward(i, "[", "]", end); - else if (stops.contains(*i)) - break; - else - ++i; - } - - if (stops.contains(*i)) - break; - - } else if (*i != ",") { - // qWarning("malformed input."); - break; - } - - if (*i == "<") { - ++tpl_nest; - } else if (*i == ">") { - ++i; - --tpl_nest; - stillType = - stillType && (tpl_nest || *i == "*" || *i == "@" || *i == "::"); - continue; - } - - if (stillType) { - if (tpl_nest || *i == "const" || *i == "::") { - ++i; - continue; - } - - if (++i == end) - break; - - stillType = *i == "*" || *i == "@" || *i == "<" || *i == "::"; - continue; - } - - ++i; - } - - // if ( i != end ) - // qDebug("@%i", end - i); - - // qDebug("};"); -} - -QTokenList concreteTemplates(const QToken &type) { - QTokenList ltpl; - - int t_beg = type.indexOf('<'), t_end = type.lastIndexOf('>'); - - if ((t_beg != -1) && (t_end != -1)) { - QToken tpl; - int t_idx = t_beg + 1, t_nest = 0; - - while (t_idx < t_end) { - if (type.at(t_idx) == '<') { - tpl += '<'; - - ++t_nest; - - } else if (type.at(t_idx) == '>') { - if (t_nest) { - --t_nest; - tpl += '>'; - - } else { - ltpl << tpl.trimmed(); - tpl.clear(); - break; - } - } else if (!t_nest && (type.at(t_idx) == ',')) { - ltpl << tpl.trimmed(); - tpl.clear(); - } else { - tpl += type.at(t_idx); - } - - ++t_idx; - } - - if (tpl.length()) - ltpl << tpl.trimmed(); - } - - return ltpl; -} - -static QByteArray trimmedType(const QByteArray &t, bool &ptr) { - if (t.isEmpty()) - return QByteArray(); - - QByteArray s = t; - - if (s.startsWith("const ")) - s.remove(0, 6); - - bool pwrd = false; - - for (int i = 0; i < s.length(); ++i) { - if (s.at(i) == '*') { - ptr = true; - s.remove(i, 1); - --i; - } else if (s.at(i) == '@') { - s.remove(i, 1); - --i; - } else if ((s.at(i) == ' ') && - !(pwrd && (((i + 1) < s.length()) - ? (isalnum(s.at(i + 1)) || (s.at(i) == '_')) - : false))) { - s.remove(i, 1); - --i; - } else if (s.at(i) == '<') { - int k = i; - - int count = 0; - - do { - if (s.at(i) == '<') - ++count; - else if (s.at(i) == '>') - --count; - - ++i; - - } while (count && (i < s.length())); - - s.remove(k, i - k); - i = k - 1; - } - - pwrd = (i == -1) ? false : (isalnum(s.at(i)) || (s.at(i) == '_')); - } - - // qDebug() << "trimmed " << t << " into " << s; - return s; -} - -static QList context(QCodeNode *p) { - QList cxt; - - if (!p) - return cxt; - - while (p->parent) { - p = p->parent; - - int t = p->type(); - - if (t == QCodeNode::Group || t == QCodeNode::Language) - break; - - cxt.prepend(p); - } - - return cxt; -} - -static void updateContext(QCodeNode *p, QList *cxt, - QList *scxt) { - if (!p) - return; - - if (cxt) - cxt->clear(); - - if (scxt) - scxt->clear(); - - while (p->parent) { - p = p->parent; - - int t = p->type(); - - if (t == QCodeNode::Group || t == QCodeNode::Language) - break; - - if (cxt) - cxt->prepend(p); - - if (scxt) - scxt->prepend(p->role(QCodeNode::Name)); - } -} - -static void updateTemplates(QCodeNode *n, const QByteArray &type, - QHash &tpl) { - if (!n) - return; - - QTokenList abs, crt; - - abs << n->role(QCodeNode::Templates).split('$'); - crt = concreteTemplates(type); - int max = qMin(abs.length(), crt.length()); - - for (int i = 0; i < crt.length(); ++i) - if (tpl.contains(crt.at(i))) - crt[i] = tpl[crt.at(i)]; - - for (int i = 0; i < max; ++i) - tpl[abs.at(i)] = crt.at(i); - -#ifdef TRACE_COMPLETION - qDebug() << "concrete templates for " << type << ": <" << abs << "> : <" - << crt << ">"; -#endif -} - -static void updateTemplates(const QList &l, const QByteArray &type, - QHash &tpl) { - if (l.isEmpty()) - return; - - QTokenList abs, crt; - - foreach (QCodeNode *n, l) { - if (!n) - continue; - - QByteArray tmp = n->role(QCodeNode::Templates); - - if (tmp.isEmpty()) - continue; - - abs << tmp.split('$'); - } - - crt = concreteTemplates(type); - int max = qMin(abs.length(), crt.length()); - - for (int i = 0; i < crt.length(); ++i) - if (tpl.contains(crt.at(i))) - crt[i] = tpl[crt.at(i)]; - - for (int i = 0; i < max; ++i) - tpl[abs.at(i)] = crt.at(i); - -#ifdef TRACE_COMPLETION - qDebug() << "concrete templates for " << type << ": <" << abs << "> : <" - << crt << ">"; -#endif -} - -QByteArray AsCompletion::functionLookup(QCodeNode *n, const QByteArray &s) { - QStack stack; - stack.push(n); - - QByteArray sig = s; - blockRemove(sig, '<', '>'); - - QTokenList abs, crt; - crt = concreteTemplates(s); - - while (stack.length()) { - QCodeNode *c = stack.pop(); - int ctype = c->type(); - QByteArray cn = c->role(QCodeNode::Name), tpl; - - if (ctype == QCodeNode::Group || - (ctype == QCodeNode::Language && cn == "AngelScript") || - (ctype == QCodeNode::Namespace && m_namespaces.contains(cn))) { - foreach (QCodeNode *child, c->children) - stack.push(child); - } else if (ctype == QCodeNode::Function && cn == sig) { - tpl = c->role(QCodeNode::Templates); - abs = tpl.split('$'); - -#ifdef TRACE_COMPLETION - qDebug("found near match : %s", cn.constData()); -#endif - // qDebug() << c->roles.split('@'); - - // not necessarily syntactically sensible but technically sensible - if (tpl.length() && (abs.length() != crt.length())) - continue; - - QByteArray type = c->role(QCodeNode::Return); - - if (tpl.length()) { -#ifdef TRACE_COMPLETION - qDebug() << "concrete templates for " << type << ": <" << abs - << "> : <" << crt << ">"; -#endif - - for (int i = 0; i < crt.length(); ++i) - substitute(type, abs.at(i), crt.at(i)); - } - - // qDebug("match -> %s", type.constData()); - return type; - } - } - - return QByteArray(); -} - -QByteArray AsCompletion::functionLookup(QCodeModel *m, const QByteArray &s) { - QList l = m->topLevelNodes(); - - foreach (QCodeNode *n, l) { - QByteArray type = functionLookup(n, s); - - if (type.length()) - return type; - } - - return QByteArray(); -} - -static QByteArray __indent; - -struct IndentLevel { - IndentLevel(QByteArray &data) : d(data) { d += ' '; } - - ~IndentLevel() { d.chop(1); } - - QByteArray &d; -}; - -#ifdef TRACE_COMPLETION -#define TRACE_UP IndentLevel __lvl(__indent); -#define TRACE(pattern, ...) \ - qDebug("%s" pattern, __indent.constData(), ##__VA_ARGS__); -#define TRACE_IF(cond, pattern, ...) \ - if (cond) \ - qDebug("%s" pattern, __indent.constData(), ##__VA_ARGS__); -#else -#define TRACE_UP -#define TRACE(pattern, ...) -#define TRACE_IF(cond, pattern, ...) -#endif - -QCodeNode *AsCompletion::lookup(const QByteArray &t) { - TRACE_UP - - if (t.isEmpty()) - return 0; - - QCodeNode *n = 0; - - TRACE("looking for %s in global db.", t.constData()) - - if (scope_file && m_locals) - n = lookup(m_locals, t, 0); - - TRACE_IF(n, "found in locals") - - if (!n && scope_local && pModel) { - n = pModel->findNode("AngelScript", t); - - TRACE_IF(n, "found in projects") - } - - if (!n && scope_system && pBackend) { - n = pBackend->findNode(t); - - TRACE_IF(n, "found in globals") - } - - // qDebug("found!"); - TRACE_IF(!n, "failed") - - return n; -} - -QCodeNode *AsCompletion::nsAwareLookup(const QByteArray &t) { - TRACE_UP - TRACE("nsAware for %s", t.constData()) - - for (int k = 0; k < m_namespaces.length(); ++k) { - const QByteArray &ns = m_namespaces.at(k); - QCodeNode *n = ns.length() ? lookup(ns) : 0; - - n = n ? lookup(n, t) : lookup(t); - - TRACE_IF(n, "success") - - if (n) - return n; - } - - TRACE("failed") - - return 0; -} - -QCodeNode *AsCompletion::lookup(QCodeNode *n, const QByteArray &t, - QList *extra) { - if (!n || t.isEmpty()) - return 0; - - TRACE_UP - TRACE("looking for %s in %s [%s].", t.constData(), - n->role(QCodeNode::Name).constData(), n->qualifiedName().constData()) - - QCodeNode *p = 0, *q = 0; - QTokenList lt = split(t, "::", '<', '>'); - QToken tok = lt.takeFirst(); - - foreach (QCodeNode *child, n->children) { - if (child && (child->role(QCodeNode::Name) == tok)) { - int type = child->type(); - - if (type == QCodeNode::Function || type == QCodeNode::Variable) - continue; - - p = child; - break; - } - } - - while (n && lt.length()) { - if (extra) - extra->append(n); - - q = 0; - tok = lt.takeFirst(); - foreach (QCodeNode *child, n->children) { - if (child && (child->role(QCodeNode::Name) == tok)) { - int type = child->type(); - - if (type == QCodeNode::Function || type == QCodeNode::Variable) - continue; - - q = child; - break; - } - } - n = q; - } - - TRACE_IF(p, "success") - TRACE_IF(!p, "failed") - - return p; -} - -QCodeNode *AsCompletion::localLookup(const QList &l, - QByteArray &tt, QByteArray &type, - bool &ptr, QHash &tpl) { - QList extra; - QCodeNode *n = - l.length() ? lookup(l.last(), tt, &extra) : nsAwareLookup(tt); - - if (!n) - return 0; - - if (n->type() == QCodeNode::Typedef) { - type = n->role(QCodeNode::Alias); - - QHash::const_iterator tpi = tpl.constBegin(); - - while (tpi != tpl.constEnd()) { - substitute(type, tpi.key(), *tpi); - ++tpi; - } - - tt = trimmedType(type, ptr); - - return decrementalLookup(l + extra, tt, type, ptr, tpl); - } - - updateTemplates(::context(n) << n, type, tpl); - - return n; -} - -QCodeNode *AsCompletion::decrementalLookup(const QList &l, - QByteArray &tt, QByteArray &type, - bool &ptr, - QHash &tpl, int k) { - if (tt.isEmpty()) - return 0; - - TRACE_UP - TRACE("decremental for %s, %s.", tt.constData(), type.constData()) - - if (k < 0) - k = l.length() + k; - - for (; k >= 0; --k) { - QList extra; - QCodeNode *n = lookup(l.at(k), tt, &extra); - - if (!n) - continue; - - if (n->type() == QCodeNode::Typedef) { - type = n->role(QCodeNode::Alias); - - QHash::const_iterator tpi = tpl.constBegin(); - - while (tpi != tpl.constEnd()) { - substitute(type, tpi.key(), *tpi); - ++tpi; - } - - tt = trimmedType(type, ptr); - - for (int j = 0; j <= k; ++j) - extra.insert(j, l.at(j)); - - return decrementalLookup(extra, tt, type, ptr, tpl); - } - - updateTemplates(::context(n) << n, type, tpl); - - return n; - } - - TRACE("global fallback") - - QCodeNode *n = nsAwareLookup(tt); - - if (n) - updateTemplates(::context(n) << n, type, tpl); - - return n; -} - -void AsCompletion::hierarchy(QCodeNode *n, QList &l, - QHash &tpl) { - if (!n) - return; - -#ifdef TRACE_COMPLETION - qDebug("computing hierarchy for %s", n->qualifiedName().constData()); -#endif - - l << n; - - QList cxt; - QTokenList acst = n->role(QCodeNode::Ancestors).split(','); - - if (acst.isEmpty()) - return; - - updateContext(n, &cxt, 0); - - foreach (QToken a, acst) { - // TODO : visibility-based filtering - - // bool bPriv = a.contains("private"); - - remove(a, "public"); - remove(a, "private"); - remove(a, "protected"); - - QHash::const_iterator tpi = tpl.constBegin(); - - while (tpi != tpl.constEnd()) { - substitute(a, tpi.key(), *tpi); - ++tpi; - } - - bool ptr = false; - QToken tt = trimmedType(a, ptr); - QCodeNode *p = decrementalLookup(cxt, tt, a, ptr, tpl); - - hierarchy(p, l, tpl); - } -} - -void AsCompletion::getMembers(QTokenList::const_iterator beg, - QTokenList::const_iterator end, - const QHash &variables, - QTokenList context, QList &nodes, - int *filter) { - QTokenList scxt; - QCodeNode *n, *tg = 0; - QList l, cxt; - QHash tpl; - QToken type, op, symbol, tt; - QTokenList::const_iterator i = beg; - bool bStat = false, bFirst = true, ptr; - QHash::const_iterator tpi; - - if (end - beg <= 1) { - type = variables["this"]; - tt = trimmedType(type, ptr); - n = lookup(tt); - - if (!n) - return; - - hierarchy(n, l, tpl); - updateContext(n, &cxt, &scxt); - - scxt << n->role(QCodeNode::Name); - - // qDebug() << context << " vs " << scxt; - - if (context == scxt) - *filter |= QCodeCompletionWidget::Private; - - nodes << l; - return; - } - - symbol = *i; - op = *(++i); - - if (op == "::") { - type = symbol; - bStat = true; - symbol = (i + 1) < end ? *(i + 1) : QToken(); - } else if (op == "." || op == "->" || op == "[") { - QHash::const_iterator vit = variables.constFind(symbol); - - if (vit == variables.constEnd()) { - vit = variables.constFind("this"); - - if (vit == variables.constEnd()) - return; - - i -= 2; - op = "->"; - } else { - symbol = (i + 1) < end ? *(i + 1) : QToken(); - } - - type = *vit; - } else if (op == "(") { - // functions - QToken ts = trimmedType(symbol, ptr); - n = nsAwareLookup(ts); - int ntype = n ? n->type() : 0; - - if (n && (ntype == QCodeNode::Class)) { - // ctors - type = symbol; - matchForward(i, "(", ")", end); - - if ((i == end) || ((i + 1) == end)) - return; - - op = *(++i); - symbol = (i + 1) < end ? *(i + 1) : QToken(); - //} else if ( n && ntype == QCodeNode::Function ) { - - } else { - // TODO : globals/locals - - if (scope_file && m_locals) - type = functionLookup(m_locals, symbol); - - if (type.isEmpty() && scope_local && pModel) - type = functionLookup(pModel, symbol); - - if (type.isEmpty() && scope_system && pBackend && pBackend->pModel) - type = functionLookup(pBackend->pModel, symbol); - - if (type.isEmpty()) { - // methods - QHash::const_iterator vit = - variables.constFind("this"); - - if (vit == variables.constEnd()) - return; - - i -= 2; - op = "->"; - type = *vit; - } else { - matchForward(i, "(", ")", end); - - if ((i == end) || ((i + 1) == end)) - return; - - op = *(++i); - symbol = (i + 1) < end ? *(i + 1) : QToken(); - - // qDebug("type %s", type.constData()); - } - } - } - - n = nsAwareLookup(join(context, "::")); - - // updateContext() start at first parent... - if (n && n->children.length()) - n = n->children.first(); - - if (n) - updateContext(n, &cxt, &scxt); - - for (int k = 0; k < m_namespaces.length(); ++k) { - const QByteArray &ns = m_namespaces.at(k); - QCodeNode *kn = ns.length() ? lookup(ns) : 0; - - if (kn) { - cxt.prepend(kn); - scxt.prepend(ns); - } - } - - do { - n = 0; - - bStat &= (op == "::"); - -#ifdef TRACE_COMPLETION - qDebug("\"%s\" \"%s\"", op.constData(), symbol.constData()); -#endif - - _overload_branching: - ptr = false; - tpi = tpl.constBegin(); - - while (tpi != tpl.constEnd()) { - substitute(type, tpi.key(), *tpi); - ++tpi; - } - - tt = trimmedType(type, ptr); - -#ifdef TRACE_COMPLETION - qDebug("looking for %s [%s : %i]", tt.constData(), type.constData(), - (int)ptr); -#endif - - n = (!bFirst && bStat) ? localLookup(cxt, tt, type, ptr, tpl) - : decrementalLookup(cxt, tt, type, ptr, tpl); - - bFirst = false; - - if (!n) { - qWarning("type not found : %s", tt.constData()); - break; - } - - updateContext(n, &cxt, &scxt); - - QList h, children; - hierarchy(n, h, tpl); - - foreach (QCodeNode *r, h) - children << r->children; - - if (op == "[") { - if (ptr) { - type.remove(type.lastIndexOf('*'), 1); - } else { - // search for operator overloading - type.clear(); - - foreach (QCodeNode *child, children) { - if (child && - (child->role(QCodeNode::Name) == "operator[]")) { - type = child->role(QCodeNode::Return); - - break; - } - } - - if (type.isEmpty()) { -#ifdef TRACE_COMPLETION - qWarning("unresolved operator overload."); -#endif - break; - } - } - - matchForward(i, "[", "]", end); - - if ((i == end) || ((i + 1) == end)) { -#ifdef TRACE_COMPLETION - qWarning("malformed completion chain."); -#endif - return; - } - - op = *(++i); - symbol = ((i + 1) < end) ? *(i + 1) : QToken(); - - continue; - } - - if (ptr && op != "->") { -#ifdef TRACE_COMPLETION - qWarning("malformed completion chain : pointer cannot mixup with " - "%s operator", - op.constData()); -#endif - break; - } - - if (op == "(") { -// search for operator overloading ?? -#ifdef TRACE_COMPLETION - qWarning("paren overloading is not supported yet."); -#endif - break; - - matchForward(i, "(", ")", end); - - if ((i == end) || ((i + 1) == end)) { -#ifdef TRACE_COMPLETION - qWarning("malformed completion chain."); -#endif - break; - } - } else if (op == "->" && !ptr) { - type.clear(); - - foreach (QCodeNode *child, children) { - if (child && (child->type() == QCodeNode::Function) && - (child->role(QCodeNode::Name) == "operator->")) { - type = child->role(QCodeNode::Return); - - break; - } - } - - if (type.isEmpty()) { -#ifdef TRACE_COMPLETION - qWarning("malformed completion chain. [syntax]"); -#endif - break; - } - - goto _overload_branching; - - } else if (((op == ".") && !ptr) || (op == "->")) { - op = (i + 2) < end ? *(i + 2) : QToken(); - - if (symbol.isEmpty()) { - tg = n; - break; - } - - type.clear(); - op = (i + 2) < end ? *(i + 2) : QToken(); - - if (op == "::") { - // filtering as in : this->BaseClass::foo() - - i += 2; - op = "."; - type = symbol; - symbol = ((i + 1) < end) ? *(i + 1) : QToken(); - - continue; - } - - QByteArray sig = symbol; - blockRemove(sig, '<', '>'); - - foreach (QCodeNode *child, children) { - if (child && (child->role(QCodeNode::Name) == sig)) { - int nt = child->type(); - - if (nt == QCodeNode::Function && op == "(") { - // TODO : support templated functions - i += 2; - matchForward(i, "(", ")", end); - type = child->role(QCodeNode::Return); - updateTemplates(child, symbol, tpl); - - break; - } else if (nt == QCodeNode::Variable && op != "(") { - ++i; - type = child->role(QCodeNode::Type); - break; - } - } - } - - if (type.isEmpty()) { -#ifdef TRACE_COMPLETION - qWarning("unable to resolve symbol."); -#endif - break; - } - } else if (op == "::") { - if (!bStat) { -#ifdef TRACE_COMPLETION - qWarning("filtering broken..."); -#endif - break; - } - - op = (i + 2) < end ? *(i + 2) : QToken(); - - if (symbol.isEmpty()) { - tg = n; - break; - } - - cxt << n; - scxt << type; - - type.clear(); - - QByteArray sig = symbol; - blockRemove(sig, '<', '>'); - - foreach (QCodeNode *child, children) { - if (child && (child->role(QCodeNode::Name) == sig)) { - int nt = child->type(); - - // qDebug("found matching symbol {%s, %s, %c}", - // symbol.constData(), op.constData(), (char)nt); - - if ((nt == QCodeNode::Function) && (op == "(")) { - // TODO : support templated functions - i += 2; - matchForward(i, "(", ")", end); - type = child->role(QCodeNode::Return); - updateTemplates(child, symbol, tpl); - - break; - } else if ((nt == QCodeNode::Variable) && (op != "(") && - (op != "::")) { - ++i; - type = child->role(QCodeNode::Type); - break; - } else if (op == "::") { - if ((nt == QCodeNode::Enum) || - (nt == QCodeNode::Class) || - (nt == QCodeNode::Namespace)) { - ++i; - type = symbol; - updateContext(child, &cxt, &scxt); - break; - } - } else if (op == "(") { - - if (nt == QCodeNode::Class) { - type = symbol; - updateContext(child, &cxt, &scxt); - i += 2; - - matchForward(i, "(", ")", end); - - if ((i == end) || ((i + 1) == end)) - return; - - break; - } - } - } - } - - if (type.isEmpty()) { -#ifdef TRACE_COMPLETION - qDebug("static failure."); -#endif - break; - } - - } else { -#ifdef TRACE_COMPLETION - qWarning("malformed completion chain."); -#endif - break; - } - - if ((i + 1) >= end) { -#ifdef TRACE_COMPLETION - qDebug("THE END ??? %s", type.constData()); -#endif - break; - } - - op = *(++i); - symbol = ((i + 1) < end) ? *(i + 1) : QToken(); - - } while (i < end); - - if (!tg) - return; - - hierarchy(tg, l, tpl); - scxt << tg->role(QCodeNode::Name); - - if (bStat) { - *filter |= QCodeCompletionWidget::KeepSubTypes | - QCodeCompletionWidget::KeepEnums; - - if ((context != scxt) && (tg->type() != QCodeNode::Namespace)) { - // TODO : take context into account before restricting that much... - - *filter |= QCodeCompletionWidget::IsStatic; - } - } - - // qDebug() << context << " vs " << scxt; - - // TODO : take friendship into account - if (context == scxt) - *filter |= QCodeCompletionWidget::Private; - - nodes << l; -} - -void AsCompletion::complete(QCodeStream *s, const QString &trig) { - if (!s /*|| !DefaultPlugin::configKey( - "QCodeCompletionEngine/AsCompletion/enabled", true)*/) - return; - - if (pPopup && pPopup->editor() != editor()) { - delete pPopup; - pPopup = nullptr; - } - - if (!pPopup) { - pPopup = new QCodeCompletionWidget(editor()); - } - - pPopup->clear(); - pPopup->setCursor(editor()->cursor()); - - // QTime time; - // time.start(); - - QAsLexer lexer; - lexer.setKeepMacroBlocks(true); - lexer.setInput(s); - - QTokenList tokens = lexer.tokens(); - -#ifdef TRACE_COMPLETION - qDebug("Tokenized..."); -#endif - - QString trigger = trig; - - // avoid segfaults by ensuring even CTRL + Space can't trigger completion on - // invalid input... - if (tokens.isEmpty() || - (!maybeIdentifier(tokens.last()) && (tokens.last() != ".") && - (tokens.last() != "->") && (tokens.last() != "::") && - (tokens.last() != "(") && trigger.isEmpty())) { -#ifdef TRACE_COMPLETION - qDebug("Invalid input..."); -#endif - - return; - } - - if (tokens.last() == "(") { - if (trigger.isEmpty()) - trigger = tokens.takeLast(); - else - return; - } - - // TODO - // scope_file = DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/file", true); - // scope_local = DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/projects", true); - // scope_system = DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/sysheaders", true); - - // qDebug("completion scope : {local, global}={%i, %i}", scope_local, - // scope_system); - -#ifdef TRACE_COMPLETION - qDebug("parsing : elapsed %i ms", time.elapsed()); -#endif - - context.clear(); - variables.clear(); - - // do context search for in-class implementations... - QTokenList::const_iterator tmp_it, class_it = tokens.constBegin(); - - while ((class_it = std::find(class_it, tokens.constEnd(), - QByteArray("class"))) != tokens.constEnd()) { - while (++class_it < tokens.constEnd()) { - if (*class_it == ";") { - // forward decl - break; - } else if (*class_it == ":") { - // def with ancestors - tmp_it = class_it; - - while (++tmp_it < tokens.constEnd()) - if (*tmp_it == "{") - break; - - if (!matchForward(tmp_it, "{", "}", tokens.constEnd())) { - // cursor within class definition... - context << *(class_it - 1); - -#ifdef TRACE_COMPLETION - qDebug("context pushed : %s", context.last().constData()); -#endif - - } else { - class_it = tmp_it + 1; - } - - break; - } else if (*class_it == "{") { - // def without ancestors - tmp_it = class_it; - - if (!matchForward(tmp_it, "{", "}", tokens.constEnd())) { - // cursor within class definition... - context << *(class_it - 1); - -#ifdef TRACE_COMPLETION - qDebug("context pushed : %s", context.last().constData()); -#endif - - } else { - class_it = tmp_it + 1; - } - - break; - } - } - } - - QToken fn; - - if (trigger == "(") { - fn = tokens.takeLast(); - - // qDebug("calltips for : %s", join(tokens, " ").constData()); - - if (tokens.isEmpty() || (tokens.last() != "." && tokens.last() != "->")) - tokens << fn; - - } else { - if (trigger.length()) - tokens << trigger.toLocal8Bit(); - else if (maybeIdentifier(tokens.last())) - pPopup->setPrefix(tokens.takeLast()); - } - - QTokenList::const_iterator tmp, l, i = tokens.constEnd(); - - bool abort = false, isId, id = false, op = false; - - while (--i >= tokens.constBegin()) { - isId = maybeIdentifier(*i); - - if (id) { - if (!isId) { - if (*i == ")") { - op = true; - if (!matchBackward(i, ")", "(", tokens.constBegin())) { - // qDebug("invalid paren nesting"); - return; - } - continue; - } else if (*i == "]") { - op = true; - if (!matchBackward(i, "]", "[", tokens.constBegin())) { - // qDebug("invalid paren nesting"); - return; - } - continue; - } else if (*i == ">") { - QToken merged; - int idx = i - tokens.constBegin(); - QTokenList::iterator rubber, stopper; - rubber = stopper = tokens.begin() + idx; - - if (!matchBackward(rubber, ">", "<", tokens.begin())) { - // qDebug("invalid paren nesting"); - return; - } - - if (rubber == tokens.begin()) { - abort = true; - break; - } - - --rubber; - - if (!isIdentifier(*rubber)) { - abort = true; - break; - } - - int n = stopper - rubber; - - do { - merged += *rubber; - rubber = tokens.erase(rubber); - } while (--n); - - merged += ">"; - - // qDebug("merged : %s", merged.constData()); - - *rubber = merged; - i = rubber; - id = false; - - continue; - } - - abort = true; - break; - } - - } else { - - if (*i != "." && *i != "->" && *i != "::") { - break; - } - - if (*i != "::") - op = true; - } - - id = !id; - } - - if (!op && (trigger == "(")) { - tokens << ";"; - i = tokens.constEnd() - 1; - } - - l = tokens.constEnd(); - - if (abort || i >= l) { -#ifdef TRACE_COMPLETION - qDebug("aborting..."); -#endif - return; - } - -#ifdef TRACE_COMPLETION - for (tmp = i + 1; tmp != l; ++tmp) - qDebug("target item : %s", tmp->constData()); -#endif - - int filter; - QList nodes; - - /* - At this point : - ] i ; l [ => tokens to type - [ begin() ; i ] => context where to extract typing data - - */ - - ++i; - - bool scope_skipped = false; - QHash parameters; - QQueue> frames; - - QTokenList::const_iterator t_beg = i, b_end = i - 1, iter; - - while (--i >= tokens.constBegin()) { - // qDebug("token : %s", i->constData()); - - if (*i == ")") { - - // qDebug("parsing paren"); - - tmp = i + 1; - - matchBackward(i, ")", "(", tokens.constBegin()); - - iter = i; - - if (i == tokens.constBegin()) - break; - - --i; - - if (isIdentifier(*i) && ((i - 1) >= tokens.constBegin()) && - (((context.length() && (*i == context.last())) || - ((context.length() > 2) && (context.last() == "::") && - (*i == context.at(context.length() - 2)))) || - isReserved(*(i - 1)) || (*(i - 1) == "&") || - (*(i - 1) == "*") || (*(i - 1) == ">") || (*(i - 1) == "~") || - (*(i - 1) == "::") || - ((i - 2) >= tokens.constBegin() && - ((*(i - 2) == "static") || (*(i - 2) == "const") || - (*(i - 2) == "::"))) || - (*tmp == "const")) && - ((*tmp == "const") || (*tmp == "{") || (*tmp == ":"))) { - // reached EOF (End Of Function) => stop data collection - // qDebug("stopping data collection..."); - - /* - 1) determine parameters list - 2) determine object context (class, namespace, ...) - */ - - if (scope_skipped) { - // looks like we're outa function scope after all... - // go back to were we belong in case the "remnants" are - // parsed into a code tree - - i = std::find(i, tokens.constEnd(), QByteArray("{")); - matchForward(i, "{", "}", tokens.constEnd()); - - break; - } - -#ifdef TRACE_COMPLETION - qDebug("function context %s", i->constData()); -#endif - - if (((i - 2) >= tokens.constBegin()) && (*(i - 1) == "~") && - (*(i - 2) == "::")) - --i; - - if ((i - 2) >= tokens.constBegin() && *(i - 1) == "::") { - // qDebug("establishing object context..."); - - do { - i -= 2; - -#ifdef TRACE_COMPLETION - qDebug("\tobject context %s::%s", i->constData(), - (i + 2)->constData()); -#endif - context << *i; - - } while ((i - 2) >= tokens.constBegin() && - *(i - 1) == "::"); - - // qDebug("context is %s", qPrintable(context.join("::"))); - } - - --tmp; - int tpl_nest = 0; - QToken t_buf, n_buf; - - while (--tmp > iter) { - if (*tmp == ">") - ++tpl_nest; - else if (*tmp == "<") - --tpl_nest; - - if (!tpl_nest && (*tmp == ",")) { - if (t_buf.length() && n_buf.length()) { -#ifdef TRACE_COMPLETION - qDebug("\tparameter : %s %s", t_buf.constData(), - n_buf.constData()); -#endif - - parameters[n_buf] = t_buf; - } - - n_buf.clear(); - t_buf.clear(); - } else if (*tmp == "=") { - n_buf.clear(); - t_buf.clear(); - } else if (n_buf.isEmpty()) { - n_buf = *tmp; - } else { - t_buf.prepend(" ").prepend(*tmp); - } - } - - if (t_buf.length() && n_buf.length()) { -#ifdef TRACE_COMPLETION - qDebug("\tparameter : %s %s", t_buf.constData(), - n_buf.constData()); -#endif - - parameters[n_buf] = t_buf; - } - - break; - } else if (*i == "for") { - // attempt to extract inline decl e.g : - // for ( int i = 0; ; ) - // foreach ( QString s, ) - -#ifdef TRACE_COMPLETION - qDebug("inline extraction from %s to %s", (i + 2)->constData(), - tmp->constData()); -#endif - - flush(i + 2, tmp, variables, - QTokenList() << ";" - << "," - << ")"); - } - - } else if (*i == "}") { - - // qDebug("framing up (skipping)"); - - // flush(i + 1, b_end, variables); - scope_skipped = true; - matchBackward(i, "}", "{", tokens.constBegin()); - - b_end = i; - - } else if (*i == "{") { - - // qDebug("framing down"); - - // flush(i+1, b_end, variables); - scope_skipped = false; - frames.enqueue(variables); - - variables.clear(); - - b_end = i - 1; - - } else if (*i == ";") { - // qDebug("encountered semicolon {"); - - // flush(i + 1, b_end, variables); - tmp = i; - bool seenEqual = false, isId = false, isPrevId = false; - - while (--i >= tokens.constBegin()) { - if (*i == "{" || *i == "}" || *i == ";") - break; - - if (seenEqual && *i == ")") - break; - - // qDebug("%s", i->constData()); - - isId = isIdentifier(*i); - - seenEqual |= (*i == "=") || (*i == "*") || (*i == "&") || - (isId && isPrevId) || - ((*i == ">") && (*(i + 1) != "(")); - - if (*i == ")") - matchBackward(i, ")", "(", tokens.constBegin()); - - if (*i == "]") - matchBackward(i, "]", "[", tokens.constBegin()); - - if (*i == ">") - matchBackward(i, ">", "<", tokens.constBegin()); - - isPrevId = isId; - } - - // qDebug("};"); - - flush(++i, tmp, variables); - - b_end = i; - } - } - - /* - At this point : - * frames is filled with variables maps ( ) - * frames are ordered, i.e calling dequeue returns the frames - in enclosing order. Thus you can do typing exactly like a C++ compiler - would do. - * parameters and object/function context are set, if any... - */ - - // here we flatten the variable hierarchy - variables.clear(); - - QHash::const_iterator it; - - while (frames.length()) { - QHash tmp = frames.dequeue(); - - for (it = tmp.constBegin(); it != tmp.constEnd(); ++it) { - if (!variables.contains(it.key())) - variables[it.key()] = *it; - } - } - - // now lets add the parameters - - for (it = parameters.constBegin(); it != parameters.constEnd(); ++it) { - variables[it.key()] = *it; - } - - // add "this" keyword - if (!context.isEmpty()) { - variables["this"] += ::join(context, "::") + "*"; - - // qDebug("this is of type : %s", qPrintable((context.join("::") + - // "*"))); - - // qDebug("\"this\" typed as %s", variables["this"].constData()); - } - - filter = QCodeCompletionWidget::Public | QCodeCompletionWidget::Protected | - QCodeCompletionWidget::KeepConst | - QCodeCompletionWidget::KeepStatic; - -#ifdef TRACE_COMPLETION - qDebug("parsing + scoping : elapsed %i ms", time.elapsed()); -#endif - - m_locals = 0; - m_namespaces.clear(); - m_namespaces << QByteArray(); - QList temp; - - QStringList lns /*= DefaultPlugin::configKey( - "QCodeCompletionEngine/AsCompletion/ns", QString()) - .split('\n')*/ - ; - - foreach (const QString &ns, lns) { - QByteArray lcns = ns.trimmed().toLocal8Bit(); - - if (!m_namespaces.contains(lcns)) - m_namespaces << lcns; - } - - // qDebug("ns {%s}", join(m_namespaces, ", ").constData()); - - if (scope_file) { - m_locals = new QCodeNode; - - // TODO : parse only the relevant part (but ALL the relevant part) - // i.e only decl before completion spot, but whole class hierarchy - // if spot inside one... - - QAsParser localParser; - - bool matchedScope = true; - int accurateScopeSize = i - tokens.constBegin(); - QTokenList::const_iterator accurateScopeEnd = tokens.constBegin(); - - while (accurateScopeEnd < i) { - if (*accurateScopeEnd == "{") { - matchedScope = - matchForward(accurateScopeEnd, "{", "}", tokens.constEnd()); - - if (!matchedScope) { - break; - } - } else { - ++accurateScopeEnd; - } - } - - if (accurateScopeEnd != i && matchedScope) { - accurateScopeSize = accurateScopeEnd - tokens.constBegin(); - } - - localParser.update(m_locals, 0, tokens, 0, accurateScopeSize, false, - &m_namespaces); - - // foreach ( QCodeNode *loc, m_locals->children ) - // qDebug("parsed : %s", loc->role(QCodeNode::Name).constData()); - - temp << m_locals; - } - - // qDebug("ns {%s}", join(m_namespaces, ", ").constData()); - - // foreach ( const QByteArray& ns, m_namespaces ) - // qDebug("ns : \"%s\"", ns.constData()); - bool extend = trigger.isEmpty() || trigger == "("; - - if (extend && (tokens.constEnd() == t_beg) && pPopup->prefix().length()) { - bool ptr = false; - QCodeNode *cxt_locals = new QCodeNode; - QHash::const_iterator vit = variables.constBegin(); - - while (vit != variables.constEnd()) { - QCodeNode *var = new QCodeNode; - var->roles = "v@"; - var->roles += vit.key(); - var->roles += "@"; - var->roles += trimmedType(*vit, ptr); - var->roles += "@"; - var->roles += QByteArray::number(QCodeNode::VISIBILITY_PUBLIC); - var->roles += "@"; - var->roles += QByteArray::number(QCodeNode::SPECIFIER_NONE); - - var->attach(cxt_locals); - - ++vit; - } - - temp << cxt_locals; - nodes << cxt_locals; - - if (m_locals) - nodes << m_locals; - } - - getMembers(t_beg, tokens.constEnd(), variables, context, nodes, &filter); - - if (extend && (tokens.constEnd() == t_beg) && pPopup->prefix().length()) { - // lets add types and fancy global stuffs - // BUT keep the "normal" lookup to make sure local/class variables will - // work as expected - - QList globs; - globs << pBackend->rootNodes() << pModel->findRootNodes("C++"); - - foreach (const QByteArray &ns, m_namespaces) - if (ns.length()) - globs << pBackend->findNode(ns) << pModel->findNode("C++", ns); - - if (globs.length()) { - filter |= QCodeCompletionWidget::Public | - QCodeCompletionWidget::KeepSubTypes | - QCodeCompletionWidget::KeepEnums | - QCodeCompletionWidget::KeepStatic; - - nodes << globs; - } - } - - if (nodes.isEmpty() && tokens.length() && (trigger == "(")) { - // qDebug("call tip extension : %s", fn.constData()); - - // extend scope for call tips (ctors) - QHash::const_iterator vit = variables.constFind(fn); - - if (vit != variables.constEnd()) { - // qDebug("type : %s", vit->constData()); - - fn = *vit; - - // stack ctor : Object instance(); - QCodeNode *n = pBackend->findNode(fn); - - if (n) - nodes << n; - - n = pModel->findNode("C++", fn); - - if (n) - nodes << n; - - } else { - // heap ctor : Object *instance = new Object(); - - QCodeNode *n = pBackend->findNode(fn); - - if (n) - nodes << n; - - n = pModel->findNode("C++", fn); - - if (n) - nodes << n; - } - } - -#ifdef TRACE_COMPLETION - qDebug("parsing + scoping + search : elapsed %i ms", time.elapsed()); -#endif - - if (nodes.length()) { - if (trigger == "(") { - QStringList tips; - - // qDebug("fn %s", fn.constData()); - - foreach (QCodeNode *n, nodes) { - foreach (QCodeNode *f, n->children) { - if (f->type() != QCodeNode::Function || - f->role(QCodeNode::Name) != fn) - continue; - - QString tip = - QString::fromLocal8Bit(f->role(QCodeNode::Arguments)) - .prepend('(') - .append(')'); - - if (!tips.contains(tip)) - tips << tip; - } - } - - if (tips.length()) { - QRect r = editor()->cursorRect(); - QDocumentCursor cursor = editor()->cursor(); - QDocumentLine line = cursor.line(); - - int hx = editor()->horizontalOffset(), - cx = line.cursorToX(cursor.columnNumber()); - - QCallTip *ct = new QCallTip(editor()->viewport()); - ct->move(cx - hx, r.y() + r.height()); - ct->setTips(tips); - ct->show(); - ct->setFocus(); - -#ifdef TRACE_COMPLETION - qDebug( - "parsing + scoping + search + pre-display : elapsed %i ms", - time.elapsed()); -#endif - } - } else { - pPopup->setTemporaryNodes(temp); - pPopup->setFilter(QCodeCompletionWidget::Filter(filter)); - pPopup->setCompletions(nodes); - -#ifdef TRACE_COMPLETION - qDebug("parsing + scoping + search + pre-display : elapsed %i ms", - time.elapsed()); -#endif - - pPopup->popup(); - } - } else { - qDeleteAll(temp); - qDebug("completion failed"); - } - -#ifdef TRACE_COMPLETION - qDebug("parsing + scoping + search + display : elapsed %i ms", - time.elapsed()); -#endif -} - -Q_DECL_UNUSED static void fetchFiles(const QDir &dir, QStringList &fl, - const QStringList &exts, bool suffixless) { - QFileInfoList il = dir.entryInfoList(QDir::Files | QDir::Dirs | - QDir::NoDotAndDotDot | QDir::Readable); - - foreach (QFileInfo info, il) { - if (info.isDir()) { - if (info.fileName() != "private") - fetchFiles(info.absoluteFilePath(), fl, exts, suffixless); - - continue; - } - - if (exts.contains(info.suffix()) || - (suffixless && info.suffix().isEmpty())) - fl << info.absoluteFilePath(); - } -} - -QCodeCompletionBackend::QCodeCompletionBackend() : pModel(0) { - pModel = new QCodeModel; - - // QString qt_headers = QLibraryInfo::location(QLibraryInfo::HeadersPath) + - // QDir::separator() + "Qt"; - - // bool enabled = DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/enabled", true); - // bool suffixless = DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/suffixless", true); - // bool sysheaders = DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/sysheaders", true); - - // if (!enabled || !sysheaders) - // return; - - // QStringList l = - // DefaultPlugin::configKey( - // "QCodeCompletionEngine/AsCompletion/pathlist", QString()) - // .split("\n"); - - QCodeSerializer serializer; - serializer.setTargetModel(pModel); - - // QDir d(Edyuk::settingsPath()); - - // foreach (QFileInfo info, d.entryInfoList(QDir::Files | QDir::Readable)) { - // if (info.suffix() != "tag") - // continue; - - // QString src; - // bool ok = false; - - // serializer.deserialize(info.absoluteFilePath(), &ok, &src, - // info.lastModified()); - - // if (ok) { - // qDebug("reloaded : %s", qPrintable(src)); - // for (int i = 0; i < l.length(); ++i) { - // QString e = l.at(i); - - // if (e.replace("\\", "/") == src) - // l.removeAt(i--); - // } - // } else { - // qDebug("loading failed : %s", - // qPrintable(info.absoluteFilePath())); - // } - // } - - QAsParser parser; - - QStringList exts = QStringList() << "h"; - - // foreach (QString d, l) { - // // parser.parseDirectory(d, exts); - // d.replace("\\", "/"); - - // QDir dir(d); - // QStringList fl; - // QString lbl = d; - - // if (d.endsWith("/include")) { - // lbl.chop(8); - // } - - // fetchFiles(dir, fl, exts, suffixless); - - // if (fl.isEmpty()) - // continue; - - // QCodeNode *g = parser.getNode(); - // g->roles = "g@" + QFileInfo(lbl).fileName().toLocal8Bit() + "@" + - // d.toLocal8Bit(); - - // qDebug("status:Building completion database for %s", qPrintable(d)); - - // foreach (const QString &f, fl) { - // QCodeDevice stream(f); - - // QCppLexer lex(&stream); - // parser.update(g, &lex, false); - // } - - // d.replace("/", "_").replace(":", "_"); - // d.prepend(Edyuk::settingsPath() + "/"); - // d.append(".tag"); - - // QFile tag(d); - - // if (!tag.open(QFile::WriteOnly | QFile::Text)) { - // qWarning("Unable to open %s for writing", qPrintable(d)); - // continue; - // } - - // QTextStream tagstream(&tag); - - // serializer.serialize(g, tagstream); - // pModel->appendTopLevelNode(g); - // } -} - -QCodeCompletionBackend::~QCodeCompletionBackend() { - delete pModel; - pModel = 0; -} - -void QCodeCompletionBackend::init() {} - -QCodeNode *QCodeCompletionBackend::findNode(const QByteArray &type) const { - return pModel ? pModel->findNode("", type) : 0; - - // return m_sysheaders.length() ? m_sysheaders.at(0)->findNode(type) : 0; -} - -QList QCodeCompletionBackend::rootNodes() const { - return pModel ? pModel->topLevelNodes() : QList(); - - // return m_sysheaders.length() ? m_sysheaders.at(0)->findNode(type) : 0; -} +void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {} diff --git a/src/class/ascompletion.h b/src/class/ascompletion.h index 5b91845..cd63acf 100644 --- a/src/class/ascompletion.h +++ b/src/class/ascompletion.h @@ -1,36 +1,16 @@ #ifndef _AS_COMPLETION_H_ #define _AS_COMPLETION_H_ -#include "control/qcodecompletionwidget.h" #include "qcodecompletionengine.h" -#include "qcodenode.h" #include class QByteArray; -class QCodeCompletionBackend { - friend class AsCompletion; - -public: - QCodeCompletionBackend(); - virtual ~QCodeCompletionBackend(); - - QList rootNodes() const; - QCodeNode *findNode(const QByteArray &type) const; - - void init(); - -private: - QCodeModel *pModel; - QStringList m_buffer, m_pathlist; -}; - class AsCompletion : public QCodeCompletionEngine { Q_OBJECT public: AsCompletion(QObject *p = nullptr); - AsCompletion(QCodeModel *m, QObject *p = nullptr); virtual ~AsCompletion(); @@ -39,52 +19,13 @@ public: virtual QString language() const override; virtual QStringList extensions() const override; - void init(); - - QCodeCompletionBackend *backend() const; - protected: - virtual void setCodeModel(QCodeModel *m) override; - virtual void complete(QCodeStream *s, const QString &trigger) override; - -public: - void hierarchy(QCodeNode *n, QList &l, - QHash &tpl); - - QCodeNode *lookup(const QByteArray &t); - QCodeNode *nsAwareLookup(const QByteArray &t); - QCodeNode *lookup(QCodeNode *n, const QByteArray &t, - QList *extra = 0); - - QCodeNode *localLookup(const QList &cxt, QByteArray &tt, - QByteArray &type, bool &ptr, - QHash &tpl); - - QCodeNode *decrementalLookup(const QList &cxt, QByteArray &tt, - QByteArray &type, bool &ptr, - QHash &tpl, - int k = -1); - - void getMembers(QList::const_iterator beg, - QList::const_iterator end, - const QHash &variables, - QList cxt, QList &l, int *filter); - - QByteArray functionLookup(QCodeNode *n, const QByteArray &s); - QByteArray functionLookup(QCodeModel *m, const QByteArray &s); + virtual void complete(const QDocumentCursor &c, + const QString &trigger) override; private: - QCodeCompletionWidget *pPopup; - QPointer pModel; - - static unsigned long instances; - static QCodeCompletionBackend *pBackend; - - QCodeNode *m_locals; - QList context; - QList m_namespaces; - QHash variables; - bool scope_local, scope_system, scope_file; + // QCodeCompletionWidget *pPopup; + // QPointer pModel; }; #endif // _CPP_COMPLETION_H_ diff --git a/src/class/asdebugger.cpp b/src/class/asdebugger.cpp index 2667df4..3f65a3c 100644 --- a/src/class/asdebugger.cpp +++ b/src/class/asdebugger.cpp @@ -56,7 +56,8 @@ void asDebugger::lineCallback(asIScriptContext *ctx) { return; const char *file = 0; - int lineNbr = ctx->GetLineNumber(0, nullptr, &file); + int col = 0; + int lineNbr = ctx->GetLineNumber(0, &col, &file); // why? // LineCallBack will be called each only a sentence, @@ -69,7 +70,8 @@ void asDebugger::lineCallback(asIScriptContext *ctx) { auto dbgContext = reinterpret_cast(ctx->GetUserData()); if (dbgContext->line == lineNbr && dbgContext->file == file && - dbgContext->stackCount == ctx->GetCallstackSize()) { + dbgContext->stackCount == ctx->GetCallstackSize() && + dbgContext->col < col) { return; } } @@ -107,6 +109,7 @@ void asDebugger::lineCallback(asIScriptContext *ctx) { Q_ASSERT(dbgContext); dbgContext->file = file; dbgContext->line = lineNbr; + dbgContext->col = col; dbgContext->stackCount = ctx->GetCallstackSize(); emit onRunCurrentLine(file, lineNbr); diff --git a/src/class/asdebugger.h b/src/class/asdebugger.h index 8d596b1..c180b63 100644 --- a/src/class/asdebugger.h +++ b/src/class/asdebugger.h @@ -133,6 +133,7 @@ private: struct ContextDbgInfo { QString file; int line = -1; + int col = -1; int stackCount = -1; }; diff --git a/src/class/languagemanager.cpp b/src/class/languagemanager.cpp index 02f94ec..172085b 100644 --- a/src/class/languagemanager.cpp +++ b/src/class/languagemanager.cpp @@ -37,6 +37,28 @@ LanguageManager::LanguageManager() { } _defaultLocale = QLocale::system(); + + if (m_langs.isEmpty()) { +#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) + if (QLocale::China == _defaultLocale.territory() +#else + if (QLocale::China == _defaultLocale.country() +#endif + ) { + QMessageBox::critical( + nullptr, QStringLiteral("程序损坏"), + QStringLiteral( + "语言文件已损坏,请尝试重装软件以解决这个问题。")); + } else { + QMessageBox::critical( + nullptr, QStringLiteral("Corruption"), + QStringLiteral("The language file has been damaged. " + "Please try reinstalling the software to " + "solve the problem.")); + } + qApp->exit(-1); + } + bool found = false; for (auto p = m_localeMap.begin(); p != m_localeMap.end(); ++p) { #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) diff --git a/src/class/qaslexer.cpp b/src/class/qaslexer.cpp deleted file mode 100644 index 31c0a0b..0000000 --- a/src/class/qaslexer.cpp +++ /dev/null @@ -1,689 +0,0 @@ -#include "qaslexer.h" -#include "qcodestream.h" - -#include -#include -#include -#include - -//#define _TRACE_FILTERING_ - -#ifdef _TRACE_FILTERING_ -static QByteArray filterIndent; - -#define FILTER_IN filterIndent += " "; -#define FILTER_OUT filterIndent.chop(1); - -#define FILTER_TRACE(fmt, data) qDebug("%s" fmt, filterIndent.constData(), data) - -#else - -#define FILTER_IN -#define FILTER_OUT - -#define FILTER_TRACE(fmt, data) - -#endif - -QHash QAsLexer::m_macros; - -QAsLexer::QAsLexer() : QCodeLexer(), bTokenized(false), bKeepMacros(false) { - // initMacros(); -} - -QAsLexer::QAsLexer(QCodeStream *s) - : QCodeLexer(s), bTokenized(false), bKeepMacros(false) { - // initMacros(); - refreshTokens(Normal); -} - -void QAsLexer::initMacros(const QTokenList &l) { - if (m_macros.count()) - return; - - // qDebug("loaded %i macros", l.count()); - - for (QToken m : l) { - m = m.trimmed(); - int idx = m.indexOf('='); - - if (idx == -1) { - m_macros[m]; - continue; - } - - m_macros[m.left(idx)] = m.mid(idx + 1); - } -} - -bool QAsLexer::keepMacroBlocks() const { return bKeepMacros; } - -void QAsLexer::setKeepMacroBlocks(bool keep) { bKeepMacros = keep; } - -void QAsLexer::setInput(QCodeStream *s, LexMode m) { - QCodeLexer::setInput(s); - - bTokenized = false; - - refreshTokens(m); -} - -QToken QAsLexer::nextToken() { - if (!bTokenized) { - qWarning("Empty token buffer (no stream passed to lexer)"); - } - - if (tokenPointer < tokenBuffer.constEnd()) - return *(tokenPointer++); - - return QToken(); -} - -QToken QAsLexer::previousToken() { - if (!bTokenized) { - qWarning("Empty token buffer (no stream passed to lexer)"); - } - - if (tokenPointer >= tokenBuffer.constBegin()) - return *(tokenPointer--); - - return QToken(); -} - -QTokenList QAsLexer::tokens() { - if (!bTokenized) { - qWarning("Empty token buffer (no stream passed to lexer)"); - } - - return tokenBuffer; -} - -int QAsLexer::lineForToken(int tokenId, int minLine) const { - // minLine = 0; - - int line = minLine; - if (minLine) - minLine = 0; - - minLine *= 2; - // qDebug("looking for token %i", tokenId); - - while (minLine < m_jumps.count()) { - if (tokenId < m_jumps.at(minLine)) - break; - - line = m_jumps.at(++minLine); - // line += m_jumps.at(++minLine); - - // qDebug("gap : %i", line); - - ++minLine; - } - - return line; -} - -template -static void s_flush(T &buffer, QList &data, bool a, - const QHash ¯os, - QList &suspicious) { - if (buffer.length() && a) { - QHash::const_iterator it = macros.constFind(buffer); - - if (it != macros.constEnd()) { - suspicious << data.count(); - } - - data << buffer; - } - - buffer.clear(); -} - -#define flush(buffer, data, include) \ - s_flush(buffer, data, include | bKeepMacros, m_macros, m_suspicious) - -static bool next(QCodeStream *s, char &ascii, QChar &uni) { - uni = ascii = s->getChar(); - - return ascii; -} - -static void previous(QCodeStream *s, char c) { s->ungetChar(c); } - -void QAsLexer::refreshTokens(LexMode m) { - if (input->contextFile().contains(QRegularExpression("[\\\\/]arch[\\\\/]"))) - return; - - int seq = 0; - int line = 0; - char c, tmp; - QChar uc, utmp; - QByteArray buffer, log, sep; - - QStack branch; - tokenBuffer.clear(); - - branch.push(true); - - QHash macros = m_macros; - - while (next(input, c, uc)) { - log += c; - - if (isspace(c)) { - flush(buffer, tokenBuffer, branch.top()); - - while (c && isspace(c)) { - if (c == '\n') { - // qDebug("EOL after %i tokens", tokenBuffer.count()); - ++line; - - if (m_jumps.count() && - m_jumps.at(m_jumps.count() - 2) == tokenBuffer.count()) - m_jumps[m_jumps.count() - 1] = line; - else - m_jumps << tokenBuffer.count() << line; // << 1; - - if (m == KeepLineSeparators) - tokenBuffer << sep; - } - - next(input, c, uc); - } - } - - switch (c) { - case '!': - case '=': - - flush(buffer, tokenBuffer, branch.top()); - - if (next(input, tmp, utmp)) { - if (tmp == '=') { - buffer += c; - buffer += tmp; - - flush(buffer, tokenBuffer, branch.top()); - - break; - } else { - previous(input, tmp); - } - } - - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(1, c); - - break; - - case '.': - do { - ++seq; - } while (next(input, tmp, utmp) && tmp == '.'); - - if (seq == 3) { - if (!(branch.top() || bKeepMacros)) - break; - - flush(buffer, tokenBuffer, branch.top()); - tokenBuffer << "..."; - previous(input, tmp); - seq = 0; - break; - } else if (tmp) { - do { - previous(input, tmp); - } while (--seq); - } - - case '~': - - case '?': - - case '(': - case '{': - case '}': - case '[': - case ']': - case ')': - - case ',': - case ';': - - // "single" characters - - if (!(branch.top() || bKeepMacros)) - break; - - flush(buffer, tokenBuffer, branch.top()); - tokenBuffer << QByteArray(1, c); - - break; - - case '^': - case '|': - case '&': - // bitwises - - flush(buffer, tokenBuffer, branch.top()); - - if (next(input, tmp, utmp)) { - if (tmp == c) { - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(2, c); - - break; - } else if (tmp == '=') { - buffer += c; - buffer += tmp; - - flush(buffer, tokenBuffer, branch.top()); - - break; - } else - previous(input, tmp); - } - - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(1, c); - - break; - - case '*': - case '%': - case '+': - case '-': - // operators - - flush(buffer, tokenBuffer, branch.top()); - - if (next(input, tmp, utmp)) { - if ((tmp == '=') || (c == '-' && tmp == '>') || - (((c == '-') || (c == '+')) && (c == tmp))) { - buffer += c; - buffer += tmp; - - flush(buffer, tokenBuffer, branch.top()); - - break; - } else - previous(input, tmp); - } - - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(1, c); - - break; - - case '<': - case '>': - // template or shift - - flush(buffer, tokenBuffer, branch.top()); - - if (next(input, tmp, utmp)) { - if (tmp == c) { - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(2, c); - - break; - } else if (tmp == '=') { - buffer += c; - buffer += tmp; - - flush(buffer, tokenBuffer, branch.top()); - - break; - } else - previous(input, tmp); - } - - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(1, c); - - break; - - case ':': - // label or scope resolution - - flush(buffer, tokenBuffer, branch.top()); - - if (next(input, tmp, utmp)) { - if (tmp == c) { - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(2, c); - - break; - } else - previous(input, tmp); - } - - if (branch.top() || bKeepMacros) - tokenBuffer << QByteArray(1, c); - - break; - - case '#': { - // macros - - flush(buffer, tokenBuffer, branch.top()); - - buffer += c; - - char prev = c; - bool first = true; - - while (next(input, tmp, utmp)) - if (!utmp.isSpace()) - break; - - buffer += tmp; - - // skip up to EOL - while (next(input, tmp, utmp)) { - if (first && utmp.isSpace()) { - first = false; - - if (buffer == "#ifdef") { - // check for __cplusplus ??? - branch.push(false); - } else if (buffer == "#ifndef") { - branch.push(branch.top()); - } else if (buffer == "#else") { - - if (branch.count() > 1) - branch.push(!branch.pop() && branch.top()); - else - qWarning("unpreced #else"); - - } else if (buffer == "#elif") { - - while (next(input, tmp, utmp)) - if (!utmp.isSpace()) - break; - - if (branch.count() > 1) - branch.top() = (tmp == '!') && branch.top(); - else - qWarning("unpreced #elif"); - - } else if (buffer == "#if") { - - while (next(input, tmp, utmp)) - if (!utmp.isSpace()) - break; - - branch.push((tmp == '!') && branch.top()); - - } else if (buffer == "#endif") { - - if (branch.count() > 1) - branch.pop(); - else - qWarning("too much #endif directives in %s", - qPrintable(input->contextFile())); - } else if (buffer == "#include") { - - if (tokenBuffer.isEmpty()) { - while (next(input, tmp, utmp)) - if (!utmp.isSpace()) - break; - - if (tmp == '\"') { - while (next(input, tmp, utmp)) { - if (tmp == '\"') - break; - } - } - } - } else if (buffer == "#define") { - buffer.clear(); - - while (next(input, tmp, utmp) && !utmp.isSpace()) { - buffer += tmp; - } - - // add local macro - macros[buffer]; - } - } - - if (tmp == '\n' && prev != '\\') { - ++line; - - // qDebug("EOL after %i tokens", tokenBuffer.count()); - - if (m_jumps.count() && - m_jumps.at(m_jumps.count() - 2) == tokenBuffer.count()) - m_jumps[m_jumps.count() - 1] = line; - else - m_jumps << tokenBuffer.count() << line; // << 1; - - buffer.clear(); - break; - } - - prev = tmp; - buffer += tmp; - } - - buffer.clear(); - - break; - } - - case '/': - // comments - - flush(buffer, tokenBuffer, branch.top()); - - if (next(input, tmp, utmp)) { - if (tmp == '/') { - // buffer += "//"; - - while (next(input, c, uc)) { - if (c == '\n') { - ++line; - // qDebug("EOL after %i tokens", - // tokenBuffer.count()); - - if (m_jumps.count() && - m_jumps.at(m_jumps.count() - 2) == - tokenBuffer.count()) - m_jumps[m_jumps.count() - 1] = line; - else - m_jumps << tokenBuffer.count() << line; // << 1; - - break; - } - // buffer += c; - } - - // flush(buffer, tokenBuffer); - - } else if (tmp == '*') { - - // buffer += "/*"; - - while (next(input, c, uc)) { - if (c == '\n') { - ++line; - // qDebug("EOL after %i tokens", - // tokenBuffer.count()); - - if (m_jumps.count() && - m_jumps.at(m_jumps.count() - 2) == - tokenBuffer.count()) - m_jumps[m_jumps.count() - 1] = line; - else - m_jumps << tokenBuffer.count() << line; // << 1; - - } else if ((c == '*') && next(input, tmp, utmp)) { - if (tmp == '/') - break; - - previous(input, tmp); - } - - // buffer += c; - } - - // buffer += "* /"; - - // flush(buffer, tokenBuffer); - - } else if (tmp == '=') { - buffer = "/="; - flush(buffer, tokenBuffer, branch.top()); - - } else { - buffer = "/"; - flush(buffer, tokenBuffer, branch.top()); - - previous(input, tmp); - } - } - - buffer.clear(); - - break; - - case '\'': - case '\"': { - flush(buffer, tokenBuffer, branch.top()); - - // quotes - bool escape = false; - - while (next(input, tmp, utmp)) { - if (tmp == '\\') { - buffer += tmp; - escape = !escape; - continue; - } - - if ((tmp == c) && !escape) - break; - - escape = false; - buffer += tmp; - } - - buffer.prepend(c); - buffer.append(c); - - flush(buffer, tokenBuffer, branch.top()); - - break; - } - - case '\0': - flush(buffer, tokenBuffer, branch.top()); - break; - - default: - - if (uc.isLetterOrNumber() || c == '_') { - // valid identifier char - - buffer += c; - } else { - // invalid id char not previously parsed - - // qWarning("=> unparsed char : \'%c\' [log=\"%s\"]", - // c, log.constData()); - - buffer.clear(); - // flush(buffer, tokenBuffer, branch.top()); - } - - break; - } - } - - flush(buffer, tokenBuffer, branch.top()); - - if (branch.count() > 1) - qWarning("Unterminated conditionnals in %s", - qPrintable(input->contextFile())); - - // lets filter that mess : - int offset = 0; - - while (m_suspicious.count()) { - int pos = m_suspicious.takeFirst() + offset; - - QHash::const_iterator it = - macros.constFind(tokenBuffer.at(pos)); - - if (it != macros.constEnd()) { - if (it->length()) { - tokenBuffer[pos] = *it; - } else { - // remove the macro and its arguments if any - tokenBuffer.removeAt(pos); - int prev = offset; - --offset; - - if (pos < tokenBuffer.count() && tokenBuffer.at(pos) == "(") { - int nest = 0; - - while (pos < tokenBuffer.count()) { - QToken tok = tokenBuffer.takeAt(pos); - - if (tok == "(") - ++nest; - else if (tok == ")") - --nest; - - --offset; - - if (!nest) - break; - } - } - - // update the gap list used to query line numbers - prev = offset - prev; - - // qDebug("removed %i suspicious tokens", -prev); - - for (int i = 0; i < m_jumps.count(); i += 2) { - if (m_jumps.at(i) <= pos) - continue; - - // qDebug("gap (%i, %i) becomes (%i, %i)", m_jumps[i], - // m_jumps[i + 1], m_jumps[i] + prev, m_jumps[i + 1]); - m_jumps[i] += prev; - } - } - } - } - - for (int i = m_jumps.count() - 2; i > 0; i -= 2) { - int j = i - 2; - - while ((j >= 0) && (m_jumps[j] == m_jumps[i])) { - // qDebug("merged gap (%i, %i) and (%i, %i)", m_jumps[i], m_jumps[i - // + 1], m_jumps[j], m_jumps[j + 1]); - m_jumps.removeAt(i); - m_jumps.removeAt(j + 1); - - i = j; - j -= 2; - } - } - - bTokenized = true; - - /* - qDebug("stream %s tokenized :\n-----", - qPrintable(input->contextFile())); - - foreach ( QToken k, tokenBuffer ) - qDebug("\t%s", k.constData()); - - qDebug("-----\n"); - */ -} diff --git a/src/class/qaslexer.h b/src/class/qaslexer.h deleted file mode 100644 index 9890988..0000000 --- a/src/class/qaslexer.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _QAS_LEXER_H_ -#define _QAS_LEXER_H_ - -#include "qcodelexer.h" - -#include - -class QAsLexer : public QCodeLexer { -public: - QAsLexer(); - QAsLexer(QCodeStream *s); - - bool keepMacroBlocks() const; - void setKeepMacroBlocks(bool keep); - - virtual void setInput(QCodeStream *s, LexMode m = Normal); - - virtual QToken nextToken(); - virtual QToken previousToken(); - - virtual QTokenList tokens(); - virtual int lineForToken(int tokenId, int minLine = 0) const; - - void initMacros(const QTokenList &l); - -protected: - void refreshTokens(LexMode m); - - QList m_jumps; - QList m_suspicious; - QTokenList tokenBuffer; - bool bTokenized, bKeepMacros; - static QHash m_macros; - QTokenList::const_iterator tokenPointer; -}; - -#endif // _QCPP_LEXER_H_ diff --git a/src/class/qasparser.cpp b/src/class/qasparser.cpp index 53dffac..4a3d27d 100644 --- a/src/class/qasparser.cpp +++ b/src/class/qasparser.cpp @@ -1,1800 +1,5 @@ #include "qasparser.h" -#include "qcodemodel.h" -#include "qcodenode.h" -#include "qcodestream.h" - -#include "qaslexer.h" - -#include -#include -#include -#include -#include - -//#define _TRACE_PARSING_ - -QByteArray join(const QList &l, QByteArray glue, int max = -1) { - int n = 0; - QByteArray out; - bool check = max != -1; - - foreach (const QByteArray &item, l) { - if (check && (++n > max)) - break; - - out += item; - out += glue; - } - - if (out.length()) - out.chop(glue.length()); - - return out; -} - -static void prettify(QByteArray &s) { - bool pwrd = false; - - for (int i = 0; i < s.length(); ++i) { - char prev = i ? s.at(i - 1) : 0; - char next = (i + 1) < s.length() ? s.at(i + 1) : 0; - bool cwrd = (i + 1) < s.length() - ? (isalnum(s.at(i + 1)) || (s.at(i) == '_')) - : false; - - if ((s.at(i) == ' ') && !(pwrd && cwrd) && (next != '=') && - (prev != '*') && (prev != '=') && (prev != '&')) { - s.remove(i, 1); - --i; - } - - pwrd = (i == -1) ? false : (isalnum(s.at(i)) || (s.at(i) == '_')); - } -} - -static QAsParser::KeywordId keyword(const char *s); - -QAsParser::QAsParser() : QCodeParser() {} +QAsParser::QAsParser(QObject *parent) : QObject(parent) {} QAsParser::~QAsParser() {} - -QString QAsParser::language() const { return "AngelScript"; } - -bool QAsParser::canParse(const QString &fn) const { - QString x = QFileInfo(fn).suffix(); - - return (x == "h") || (x == "hpp") || (x == "hxx"); -} - -bool isReserved(const QToken &tok) { - static QTokenList reserved; - - if (reserved.isEmpty()) { - reserved << "auto" - << "bool" - << "break" - << "case" - << "catch" - << "char" - << "class" - << "const" - << "continue" - << "do" - << "default" - << "delete" - << "double" - << "else" - << "enum" - << "explicit" - << "extern" - << "float" - << "for" - << "friend" - << "goto" - << "if" - << "inline" - << "int" - << "long" - << "mutable" - << "namespace" - << "new" - << "operator" - << "private" - << "protected" - << "public" - << "register" - << "return" - << "short" - << "signed" - << "static" - << "struct" - << "switch" - << "sizeof" - << "template" - // << "this" - << "throw" - << "try" - << "typedef" - << "typename" - << "union" - << "unsigned" - << "using" - << "virtual" - << "void" - << "while"; - } - - return reserved.contains(tok); -} - -bool maybeIdentifier(const QToken &tok) { - bool isId = true; - - if (isId) { - for (int idx = 0; idx < tok.length(); idx++) { - char c = tok.at(idx); - - isId &= isalnum(c) || (c == '_'); - } - } - - return isId; -} - -bool isIdentifier(const QToken &tok) { - return maybeIdentifier(tok) && !isReserved(tok); -} - -template -static void flush(T &buffer, QList &data) { - if (buffer.length()) { - data << buffer; - buffer.clear(); - } -} - -static void match(const QTokenList &list, int &l, int l_end, char beg, char end, - QTokenList endCond = QTokenList()) { - int count = 0; - - --l; - - while (++l < l_end) { - QToken t = list.at(l); - char tc = t.at(0); - - if (endCond.contains(t)) { - break; - } else if (t.length() != 1) { - continue; - } else if (tc == beg) { - ++count; - } else if (tc == end) { - --count; - - if (count <= 0) - break; - } - } -} - -static void dump(QTokenList &l) { - QToken dump_array; - - for (const QToken &ba : l) - dump_array += " " + ba; - - l.clear(); - -#ifdef _TRACE_PARSING_ - qDebug("buffer dump : {%s}", dump_array.constData()); -#endif -} - -inline bool filter(int &i, int end) { return i < end; } - -QCodeLexer *QAsParser::lexer(QCodeStream *s) { return new QAsLexer(s); } - -/*! - \brief Updates the content of a code node according to a code source. - This function can be very handy when dealing with large set of source - data whose representation shall be dynamically modified when the source - itself changes. However it is *VERY IMPORTANT* to provide the - relevant source and only it... -*/ -void QAsParser::update(QCodeNode *n, QCodeLexer *l, bool check) { - if (!n || !l) - return; - - sContext = l->contextFile(); - -#ifdef _TRACE_PARSING_ - qDebug("updating context %s in %s", qPrintable(sContext), - n->role(QCodeNode::Name).constData()); -#endif - - if (true) { - QByteArray cxt = sContext.toLocal8Bit(); - - QStack nodes; - nodes.push(n); - - while (nodes.count()) { - QCodeNode *node = nodes.pop(); - int t = node->type(); - - // qDebug(" * %s, context : %s", - // node->role(QCodeNode::Name).constData(), - // node->context().constData()); - - if (node->context() == cxt) { - if (!check) { - // qDebug("skipping duplicate cxt %s", cxt.constData()); - return; - } - - // qDebug("removed node %s (in {0x%x, 0x%x})", - // node->role(QCodeNode::Name).constData(), node->parent, - // node->model); - - // node->clear(); - node->detach(); - - if (node != n) { - // qDebug("deleted node %s", - // node->role(QCodeNode::Name).constData()); - - delete node; - } - } else if ((t == QCodeNode::Group) || (t == QCodeNode::Language) || - (t == QCodeNode::Namespace)) { - - foreach (QCodeNode *child, node->children) { - if (child) - nodes.push(child); - } - } - } - // qDebug("updating cxt %s", cxt.constData()); - } else { -#ifdef _TRACE_PARSING_ - qWarning("no check..."); -#endif - } - - QTokenList data = l->tokens(); - -#ifdef _TRACE_PARSING_ - /* QTextStream out(stdout); - - out << "Tokens after filtering..." << endl << endl; - - foreach ( const QToken& token, data ) - out << token << endl; - */ -#endif - - update(n, l, data, 0, data.count()); -} - -/*! - \brief Updates a -*/ -void QAsParser::update(QCodeNode *n, QCodeLexer *l, QTokenList &tokens, int id, - int end, bool bNeedCxt, QTokenList *ns) { - if (!n || id == end) { -#ifdef _TRACE_PARSING_ - qWarning("QCppParser::update() => bad input..."); -#endif - - return; - } - - QByteArray sContext = this->sContext.toLocal8Bit(); - - int line = l ? 0 : -1; - int type = n->type(); - QCodeNode *pScope = n; - QStack nest; - QTokenList buffer_unused, toSkip, ltemplates; - int first, last = id; - QCodeNode::NodeVisibility visibility = QCodeNode::VISIBILITY_DEFAULT; - - if (type == QCodeNode::Class) { - visibility = QCodeNode::VISIBILITY_PRIVATE; - } else if ((type == QCodeNode::Enum) || (type == QCodeNode::Namespace)) { - visibility = QCodeNode::VISIBILITY_PUBLIC; - } - - while (id < end) { - // if ( !filter(i, end) ) - // break; - - QToken token = tokens.at(id); - KeywordId k = keyword(token.constData()); - - if (l) - line = l->lineForToken(id, line); - - // qDebug("\"%s\"", token.constData()); - - switch (k) { - case KEYWORD_CLASS: { - if (ltemplates.count() == 1 && ltemplates.at(0).isEmpty()) { - // specialization : discard - buffer_unused.clear(); - - do { - ++id; - } while (id < end && tokens.at(id) != "{"); - - break; - } - - last = id; - - while (filter(++id, end)) { - if (tokens.at(id) == ":" || tokens.at(id) == "{" || - tokens.at(id) == ";") - break; - } - - if (id >= end || tokens.at(id) == ";") { - if ((id - last) == 2) { -#ifdef _TRACE_PARSING_ - qDebug("forward declaration of %s.", - tokens.at(id - 1).constData()); -#endif - last = id + 1; - } else { -#ifdef _TRACE_PARSING_ - qDebug("twisted decl."); -#endif - id = ++last; - } - - buffer_unused.clear(); - break; - } - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"class\" in %s", - sContext.constData()); - dump(buffer_unused); - ++id; - break; - } - - QToken name; - - if ((id - last) > 1) { - if ((id - last) > 2 && tokens.at(id - 1) == ">") { -#ifdef _TRACE_PARSING_ - qWarning("skipped %s", (tokens.at(id - 1) == ">") - ? "template specialization" - : "malformed class decl"); -#endif - break; - } - - name = tokens.at(id - 1); - - if (!isIdentifier(name)) { - qWarning("Syntax error : class name is a reserved keyword"); - break; - } - - } else { - name = ""; - } - - QByteArray roles = "c@"; - -#ifdef _TRACE_PARSING_ - qDebug("%s %s", (k == KEYWORD_STRUCT) ? "struct" : "class", - name.constData()); -#endif - - roles += name; - roles += "@"; - - // QList ancestors; - QByteArray rule, drule = "private"; - - if (tokens.at(id) == ":") { - while (filter(++id, end)) { - if (tokens.at(id) == "{") - break; - // else if ( tokens.at(id) == "," ) - // continue; - - if (tokens.at(id) == "public") { - ++id; - rule = "public"; - } else if (tokens.at(id) == "protected") { - ++id; - rule = "protected"; - } else if (tokens.at(id) == "private") { - ++id; - rule = "private"; - } else { - rule = drule; - } - - if (id >= end || tokens.at(id) == "{") - break; - - rule += " " + tokens.at(id); - int tpl_nest = 0; - - while (++id < end) { - if (tokens.at(id) == "{") { - break; - } else if (!tpl_nest && tokens.at(id) == ",") { - rule += tokens.at(id); - ++id; - break; - } else { - rule += " " + tokens.at(id); - - if (tokens.at(id) == "<") - ++tpl_nest; - else if (tokens.at(id) == ">") - --tpl_nest; - } - } - - // ancestors << rule; - - prettify(rule); - -#ifdef _TRACE_PARSING_ - qDebug("ancestor : %s", rule.constData()); -#endif - - roles += rule; - - if (tokens.at(id) == "{") - break; - } - } - - // room for friends... - roles += "@"; - - // templates - roles += "@"; - - if (ltemplates.count()) { - // qDebug("class %s", name.constData()); - roles += ::join(ltemplates, "$"); - ltemplates.clear(); - } - - // context - if (bNeedCxt) - roles += "@" + sContext; - - // TODO : this is an update func, check for existing node instead - // or clear all nodes before processing code... - - QCodeNode *c = getNode(); - c->line = line; - c->roles = roles; - - // if ( l ) qDebug("class at line %i", line); - - c->attach(pScope); - - if (tokens.at(id) == "{") { - // parse members - last = id; - - match(tokens, id, end, '{', '}'); - - if (id >= end) - id = end - 1; - -#ifdef _TRACE_PARSING_ - qDebug("{"); -#endif - update(c, l, tokens, last + 1, id, false); -#ifdef _TRACE_PARSING_ - qDebug("}"); -#endif - - if (tokens.at(id) == "}") { - if ((id + 1 >= end) || (tokens.at(id + 1) == ";")) { - ++id; - } else if (id < end) { - // subsequent variable decl - buffer_unused.clear(); - buffer_unused << name; - - ++id; - break; - } else { - qWarning("Syntax error in class definition : " - "missing semi-colon at end of input in %s", - sContext.constData()); - } - } else { - qWarning("Syntax error in class definition : " - "missing close bracket at end of input in %s", - sContext.constData()); - } - } - - last = ++id; - buffer_unused.clear(); - break; - } - - case KEYWORD_ENUM: { - ltemplates.clear(); - - QByteArray name; - - if (((id + 1) < end && tokens.at(id + 1) != "{") && - ((id + 2) < end && tokens.at(id + 2) != "{")) { - // twisted variable declaration... - ++id; - break; - } - - if (tokens.at(id + 1) == "{") { - // anonymous enum - name = ""; - } else if (tokens.at(id + 2) == "{") { - // named enum - name = tokens.at(++id); - } else { - qWarning("syntax error : expected \'{\' after \"enum\" in %s", - sContext.constData()); - buffer_unused.clear(); - ++id; - break; - } - - ++id; - first = id; - - match(tokens, id, end, '{', '}', QList() << ";"); - - if (buffer_unused.count()) { - qWarning("syntax error : expecting \';\' before \"enum\" in %s", - sContext.constData()); - dump(buffer_unused); - break; - } - -#ifdef _TRACE_PARSING_ - qDebug("enum %s", name.constData()); -#endif - - QCodeNode *en = getNode(); - en->line = line; - en->roles = - QByteArray("e@") + name + "@@" + QByteArray::number(visibility); - - // if ( l ) qDebug("enum at line %i", line); - - if (bNeedCxt) - en->roles += "@" + sContext; - - bool ok, gettingName = true; - QByteArray lastVal, eid, val; - int lastNum = -1, lastValCount = 0; - - while (++first < id) { - if (tokens.at(first) == "," || tokens.at(first) == "}") { - if (eid.isEmpty()) - continue; - - if (val.isEmpty()) { - if (lastVal.length()) - val = lastVal + " + " + - QByteArray::number(++lastValCount); - else - val = QByteArray::number(++lastNum); - } else { - int num = val.toInt(&ok); - - if (ok) { - lastNum = num; - lastVal.clear(); - } else { - lastVal = val; - lastValCount = 0; - } - } - - QCodeNode *enumerator = getNode(); - - enumerator->roles = QByteArray("r@") + eid + "@" + val; - enumerator->attach(en); - -#ifdef _TRACE_PARSING_ - qDebug(" %s = %s", eid.constData(), val.constData()); -#endif - - eid.clear(); - val.clear(); - - gettingName = true; - - } else if ((tokens.at(first) == "=") && gettingName) { - gettingName = false; - } else if (gettingName) { - eid = tokens.at(first); - } else { - if (val.length()) - val += ' '; - - val += tokens.at(first); - } - } - - if (eid.length()) { - if (val.isEmpty()) { - if (lastVal.length()) - val = lastVal + " + " + - QByteArray::number(++lastValCount); - else - val = QByteArray::number(++lastNum); - } else { - int num = val.toInt(&ok); - - if (ok) { - lastNum = num; - lastVal.clear(); - } else { - lastVal = val; - lastValCount = 0; - } - } - - QCodeNode *enumerator = getNode(); - - enumerator->roles = QByteArray("r@") + eid + "@" + val; - enumerator->attach(en); - -#ifdef _TRACE_PARSING_ - qDebug(" %s = %s", eid.constData(), val.constData()); -#endif - } - - en->attach(pScope); - ++id; - - break; - } - - case KEYWORD_NAMESPACE: { - ltemplates.clear(); - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"namespace\" in %s", - sContext.constData()); - buffer_unused.clear(); - - break; - } - - QList names; - - do { - ++id; - - names << tokens.at(id); - - ++id; - } while (id < end && tokens.at(id) == "::"); - - if (tokens.at(id) != "{") { - qDebug( - "Syntax error : expected \'{\' after \"namespace\" in %s", - sContext.constData()); - break; - } - - first = id + 1; - buffer_unused.clear(); - match(tokens, id, end, '{', '}'); - -#ifdef _TRACE_PARSING_ - qDebug("namespace(s) :"); - - foreach (const QByteArray &n, names) - qDebug("\t%s", n.constData()); - -// qDebug("namespace : %s", qPrintable(names.join("::"))); -#endif - - QCodeNode *p = pScope, *n = 0; - - while (names.count()) { - foreach (n, p->children) { - if ((n->type() == QCodeNode::Namespace) && - (n->role(QCodeNode::Name) == names.first())) - break; - - n = 0; - } - - QByteArray name = names.takeAt(0); - - if (name.endsWith("Private")) { -// suffixing class/namespaces name is a convention used -// by Qt to kinda hide all dirty code -// for this reason (and mostly because it confused the -// parser when modelizing Qt4 sources) such namespaces are -// skipped... -#ifdef _TRACE_PARSING_ - qDebug("skipped private namespace %s.", name.constData()); -#endif - - ++id; - break; - } - - if (!n) { - n = getNode(); - n->roles = QByteArray("n@") + name; - - n->attach(pScope); - } - } - -#ifdef _TRACE_PARSING_ - qDebug("{"); -#endif - update(n, l, tokens, first, id, true); -#ifdef _TRACE_PARSING_ - qDebug("}"); -#endif - ++id; - - break; - } - - case KEYWORD_TYPEDEF: { - ltemplates.clear(); - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"typedef\" in %s", - sContext.constData()); - dump(buffer_unused); - ++id; - break; - } - - ++id; - - switch (keyword(tokens.at(id))) { - case KEYWORD_ENUM: { - ++id; - - QByteArray name; - - if (tokens.at(id) == "{") { - // typedef anonymous as something - - first = id + 1; - - match(tokens, id, end, '{', '}'); - - last = id; - - if (id < end && tokens.at(id) != ";") - name = tokens.at(id); - else - ++id; - - } else { - // typedef something as itself - // => weird construct but can happen... - - name = tokens.at(id); - - first = id + 1; - - // match(tokens, id, end, '{', '}'); - - last = id; - ++id; - } - - // at this point : - // -> first : first definition elem - // -> last : closing bracket after last definition elem - // -> i : end token : should be ';' - // name : struct/enum/union name - - /* - if ( !filter(i, end) || tokens.at(id) != ";" ) - { - qWarning("expected \';\' after \"typedef\""); - } - */ - - while ((id < end) && (tokens.at(id) != ";")) - ++id; - - break; - } - - default: - // regular typedef - QByteArray name, alias; - - while ((id < (end - 1)) && (tokens.at(id + 1) != ";")) { - if (alias.length()) - alias += ' '; - - alias += tokens.at(id); - ++id; - } - - name = tokens.at(id); - - if (name == ")") { - // special case : pointer to function - break; - } - -#ifdef _TRACE_PARSING_ - qDebug("typedef %s", name.constData()); -#endif - - QCodeNode *td = getNode(); - td->line = line; - td->roles = QByteArray("t@") + name + "@" + alias + "@" + - QByteArray::number(visibility); - - // if ( l ) qDebug("typedef at line %i", line); - - if (bNeedCxt) - td->roles += "@" + sContext; - - td->attach(pScope); - - break; - } - - ++id; - buffer_unused.clear(); - - break; - } - - case KEYWORD_FRIEND: { - ltemplates.clear(); - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"friend\" in %s", - sContext.constData()); - dump(buffer_unused); - ++id; - break; - } - -#ifdef _TRACE_PARSING_ - qDebug("friendship."); -#endif - - QByteArray friendship_target; - - ++id; - - while ((id < end) && (tokens.at(id) != ";")) { - if (friendship_target.length()) - friendship_target += ' '; - - friendship_target += tokens.at(id); - ++id; - } - - if (pScope->type() == QCodeNode::Class) { - QByteArray role = pScope->role(QCodeNode::Friends); - - if (role.length()) - role += "#"; - - prettify(friendship_target); - - role += friendship_target; - - pScope->setRole(QCodeNode::Friends, role); - } - - if (id != end) - ++id; - - break; - } - - case KEYWORD_USING: { - ltemplates.clear(); - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"using\" in %s", - sContext.constData()); - dump(buffer_unused); - - while ((id < end) && (tokens.at(id) != ";")) - ++id; - - break; - } - -#ifdef _TRACE_PARSING_ - qDebug("using directive."); -#endif - - if (ns && ((id + 1) < end) && (tokens.at(id + 1) == "namespace")) { - id += 2; - QByteArray tmpns; - - while ((id < end) && (tokens.at(id) != ";")) { - tmpns += tokens.at(id); - ++id; - } - - ns->append(tmpns); - } else { - while ((id < end) && (tokens.at(id) != ";")) - ++id; - } - - if (id < end) - ++id; - - break; - } - - case KEYWORD_TEMPLATE: { - ltemplates.clear(); - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"template\" in %s", - sContext.constData()); - dump(buffer_unused); - - match(tokens, ++id, end, '<', '>'); - ++id; - break; - } - -#ifdef _TRACE_PARSING_ - qDebug("template directive."); -#endif - - QToken buffer; - int tmp = ++id; - - match(tokens, tmp, end, '<', '>'); - - if (tmp == end) - break; - - int nest = 0; - bool skipFirst = true; - - while (id != tmp) { - ++id; - - if (tokens.at(id) == "<") { - ++nest; - } else if (tokens.at(id) == ">") { - if (nest) { - --nest; - } else { -#ifdef _TRACE_PARSING_ - qDebug(" %s", buffer.constData()); -#endif - - ltemplates << buffer; - buffer.clear(); - break; - } - } else if (!nest && (tokens.at(id) == ",")) { -#ifdef _TRACE_PARSING_ - qDebug(" %s", buffer.constData()); -#endif - - ltemplates << buffer; - buffer.clear(); - skipFirst = true; - } else if (skipFirst) { - skipFirst = false; - } else { - if (buffer.length()) - buffer += " "; - - buffer += tokens.at(id); - } - } - - id = ++tmp; - break; - } - - case KEYWORD_EXTERN: { - ltemplates.clear(); - - if (buffer_unused.count()) { - qWarning( - "Syntax error : expecting \';\' before \"extern\" in %s", - sContext.constData()); - dump(buffer_unused); - - ++id; - break; - } - -#ifdef _TRACE_PARSING_ - qDebug("extern."); -#endif - - if ((id + 1) < end && tokens.at(id + 1).startsWith("\"")) { - // extern "C/C++/..." { ... } - ++id; - - last = id + 1; - match(tokens, last, end, '{', '}'); - - if (tokens.at(id) == "\"C\"" || tokens.at(id) == "\"C++\"") { - update(pScope, l, tokens, id + 2, last, true); - } - - id = last + 1; - - } else { - // extern variable/function... - ++id; - } - - break; - } - - default: { - if (token.endsWith("_EXPORT") || token.contains("_EXPORT_")) { -#ifdef _TRACE_PARSING_ - qDebug("skipped annoying export token : %s", token.constData()); -#endif - - ++id; - continue; - } else if (toSkip.contains(token)) { -#ifdef _TRACE_PARSING_ - qDebug("skipped problematic token : %s", token.constData()); -#endif - - ltemplates.clear(); - buffer_unused.clear(); - - ++id; - continue; - } else if (token == "{") { - - ltemplates.clear(); - // buffer_unused.clear(); - - if (buffer_unused.count() && buffer_unused.last() == "=") { -#ifdef _TRACE_PARSING_ - qDebug("skipped problematic data block"); -#endif - buffer_unused.removeLast(); - } else { -#ifdef _TRACE_PARSING_ - qDebug("skipped problematic code block"); -#endif - buffer_unused.clear(); - } - - match(tokens, id, end, '{', '}'); - ++id; - - continue; - - } else if (token == ";") { - if (buffer_unused.count()) { - if (keyword(buffer_unused.last()) == KEYWORD_NONE) { - QByteArray type; - - int templateCount = 0; - - QTokenList::const_iterator - ba = buffer_unused.constBegin(), - buffer_end = buffer_unused.constEnd() /*, - buffer_beg = buffer_unused.constBegin()*/ - ; - - QCodeNode::TypeSpecifier ts = QCodeNode::SPECIFIER_NONE; - - int nodeType = pScope->type(); - - bool cont = false, - inClass = (nodeType == QCodeNode::Class); - - if (!inClass) { - if (*ba == "extern") - ts |= QCodeNode::SPECIFIER_EXTERN; - else if (*ba == "auto") - ts |= QCodeNode::SPECIFIER_AUTO; - else if (*ba == "const") - ts |= QCodeNode::SPECIFIER_CONST; - else - --ba; - } else { - if (*ba == "const") - ts |= QCodeNode::SPECIFIER_CONST; - else - --ba; - } - - ++ba; - - if (ba >= buffer_end) { - buffer_unused.clear(); - break; - } - - do { - if (*ba == "<") { - cont = true; - ++templateCount; - } else if (*ba == ">") { - --templateCount; - cont = templateCount; - } else if ((*ba == "::") || - (((ba + 1) < buffer_end) && - *(ba + 1) == "::") || - (((ba + 1) < buffer_end) && - *(ba + 1) == "<")) { - cont = true; - } else if (inClass && - (*ba == "const" || *ba == "volatile")) { - cont = true; - } else if (*ba == "unsigned" || *ba == "signed") { - cont = true; - } else if (*ba == "long" && - ((((ba + 1) < buffer_end) && - *(ba + 1) == "int") || - (((ba + 1) < buffer_end) && - *(ba + 1) == "long") || - (((ba + 1) < buffer_end) && - *(ba + 1) == "double"))) { - cont = true; - } else { - cont = templateCount; - } - - if (type.length()) - type += " "; - - type += *ba; - - } while (++ba < buffer_end && cont); - - --ba; - QByteArray tmp; - QByteArray tok; - bool b_val_skip = false; - - while (++ba < buffer_end) { - if (*ba == "::" || *ba == "<") { - // syntax pitfall... - break; - } else if (*ba == "=" || *ba == ":" || *ba == "(") { - // ctor/init/assignment - int assign_nest = 0; - - do { - if (*ba == "<" || *ba == "(") - ++assign_nest; - else if (*ba == ">" || *ba == ")") - --assign_nest; - - ++ba; - } while ((ba + 1) < buffer_end && - (*ba != "," || assign_nest) && - *ba != ";"); - - tok = ","; - } else if ((ba + 1) == buffer_end) { - if (!b_val_skip) { - if (tmp.isEmpty()) - tmp += *ba; - else - tmp += " " + *ba; - } - - tok = ","; - } else { - tok = *ba; - } - - if (tok == ",") { - int refs = tmp.count('&'); - int stars = tmp.count('*'); - - tmp.replace('*', QByteArray()); - tmp.replace('&', QByteArray()); - - type += QByteArray(stars, '*'); - type += QByteArray(refs, '&'); - - prettify(type); - -#ifdef _TRACE_PARSING_ - qDebug("%s %s;", type.constData(), - tmp.trimmed().constData()); -#endif - - QCodeNode *var = getNode(); - var->line = line; - var->roles = QByteArray("v@") + tmp.trimmed() + - "@" + type + "@" + - QByteArray::number(visibility) + - "@" + QByteArray::number(ts); - - // if ( l ) qDebug("variable at line %i", line); - - if (bNeedCxt) - var->roles += "@" + sContext; - - var->attach(pScope); - - tmp.clear(); - b_val_skip = false; - } else if (b_val_skip) { - } else if (tok == "=") { - b_val_skip = true; - } else if (tmp.isEmpty()) { - tmp += tok; - } else { - tmp += " " + tok; - } - } - } - - ltemplates.clear(); - buffer_unused.clear(); - } - } else if (buffer_unused.count()) { - - int equ_idx = buffer_unused.indexOf("="); - bool assign = equ_idx != -1; - - if (assign && buffer_unused.count() >= 1) - assign = equ_idx != buffer_unused.count() - 1; - - if (assign && buffer_unused.count() >= 2) - assign = buffer_unused.at(buffer_unused.count() - 2) != - "operator"; - - if (token == "(") { - // make sure we don't mistake var decl fro func decl... - first = last = id; - match(tokens, last, end, '(', ')', - QList() << ";"); - - // variable decl with ctor (most probably...) - if (last == end || (last + 1) == end || - tokens.at(last + 1) == "," || tokens.at(last) == ";") - assign = true; - } - - if (token == ":") { - bool visa = false; - - if (buffer_unused.last() == "slots") { - // TODO : slots visibility flag... - visa = true; - buffer_unused.removeLast(); - } - - if (buffer_unused.last() == "public") { - visa = true; - visibility = QCodeNode::VISIBILITY_PUBLIC; - } else if (buffer_unused.last() == "protected") { - visa = true; - visibility = QCodeNode::VISIBILITY_PROTECTED; - } else if (buffer_unused.last() == "private") { - visa = true; - visibility = QCodeNode::VISIBILITY_PRIVATE; - } else { - // qWarning("weird syntactic construct in %s", - // sContext.constData()); - } - - if (visa) { -#ifdef _TRACE_PARSING_ - qDebug("[visibility changed to : %s]", - buffer_unused.last().constData()); -#endif - - buffer_unused.clear(); - } else { - // assumme it's all about in-decl variable init - } - } else if ((token == "(") && ((id + 1) < end) && - (tokens.at(id + 1) != "*") && !assign) { - // parse members - first = id + 1; - - // qDebug("looking for matching paren..."); - - match(tokens, id, end, '(', ')', - QList() << ";"); - - if (id == end) { - buffer_unused.clear(); - - break; - } - - last = id; - ++id; - - // qDebug("recursive argument parsing"); - - if ((id >= end) // out of range - || (tokens.at(last) == - ";") // out of range and/or malformed code - || ( // get rid of macros - (tokens.at(id) != ";") // !decl - && (tokens.at(id) != "{") // !impl - && (tokens.at(id) != ":") // !ctor impl - && (buffer_unused.count() == 1)) || - buffer_unused.isEmpty()) { - buffer_unused.clear(); - - break; - } - - QCodeNode::FunctionQualifier fq = QCodeNode::QUALIFIER_NONE; - - int pref_idx = buffer_unused.indexOf("explicit"); - - if (pref_idx != -1) - buffer_unused.removeAt(pref_idx); - - QByteArray name; - QByteArray retval; - QByteArray arg_buff; - QList args; - bool isCtorDtor = false; - int idx = buffer_unused.indexOf("operator"); - - if (idx != -1) { - name = "operator"; - - buffer_unused.removeAt(idx); - - if (idx) { - while (buffer_unused.count() > idx) { - name += ' '; - name += buffer_unused.takeAt(idx); - } - } else { - // conversion operator e.g : - // operator bool () const; - // leave buffer as is so that retval computation - // succeeds - while (idx < buffer_unused.count()) { - name += ' '; - name += buffer_unused.at(idx); - ++idx; - } - } - } else if (buffer_unused.last() == ">") { - int templates = 1; - - while (buffer_unused.count()) { - QByteArray s = buffer_unused.takeLast(); - - name.prepend(s + " "); - - if (!templates) - break; - - if (s == ">") - ++templates; - else if (s == "<") - --templates; - } - - if (ltemplates.count() == 1 && - ltemplates.at(0).isEmpty()) { - // specialization : discard - buffer_unused.clear(); - - break; - } - } else { - name = buffer_unused.takeLast(); - } - - // maybe ctor or dtor - - if ((pScope->type() == QCodeNode::Class) && - (name == pScope->role(QCodeNode::Name))) { - isCtorDtor = true; - - if (buffer_unused.count() && - buffer_unused.last() == "~") { - name.prepend("~"); - buffer_unused.removeAt(buffer_unused.count() - 1); - } - - if (buffer_unused.count() && - buffer_unused.at(0) == "abstract") { - fq |= QCodeNode::QUALIFIER_ABSTRACT; - buffer_unused.removeAt(0); - } - - buffer_unused.clear(); - } - - if (!isCtorDtor) { - if (buffer_unused.isEmpty()) { -// probably macro stuff... -#ifdef _TRACE_PARSING_ - qDebug("skipped supposed macro : %s", - name.constData()); -#endif - break; - } - - // anything else - if (buffer_unused.at(0) == "extern") - fq |= QCodeNode::QUALIFIER_EXTERN; - else - goto skip_qualifiers; - - buffer_unused.removeAt(0); - } - - skip_qualifiers: - - foreach (const QToken &ba, buffer_unused) - retval += (retval.length() ? " " + ba : ba); - - if ((last - first) >= 1) { - bool bParamAbort = false; - bool bFirstParamTok = true; - int tpl_nest = 0; - - do { - if (bFirstParamTok && - !maybeIdentifier(tokens.at(first)) && - tokens.at(first) != "...") { - bParamAbort = true; - break; - } - - if (!tpl_nest && tokens.at(first) == ",") { - prettify(arg_buff); - flush(arg_buff, args); - bFirstParamTok = true; - } else { - bFirstParamTok = false; - arg_buff += (arg_buff.isEmpty() - ? tokens.at(first) - : " " + tokens.at(first)); - - if (tokens.at(first) == "<") - ++tpl_nest; - else if (tokens.at(first) == ">") - --tpl_nest; - } - } while (++first < last); - - if (bParamAbort) { - break; - } - - prettify(arg_buff); - flush(arg_buff, args); - } - - while (id < end) { - if (tokens.at(id) == ";") { - break; // end of decl - } else if (tokens.at(id) == ":") { - // handle ctor special construct - while ((id < end) && (tokens.at(id) != "{")) - ++id; - - match(tokens, id, end, '{', '}'); // end of impl - break; - } else if (tokens.at(id) == "{") { - match(tokens, id, end, '{', '}'); // end of impl - break; - } else if (tokens.at(id) == "const") - fq |= QCodeNode::QUALIFIER_CONST; - - ++id; - } - - if (!retval.endsWith("::") && - !retval.endsWith(":: ~") // small quirk handling... - ) { - - prettify(name); - prettify(retval); - -#ifdef _TRACE_PARSING_ - qDebug("func %s", name.constData()); - - qDebug("("); - - foreach (const QByteArray &a, args) - qDebug(" %s", a.constData()); - - qDebug(")"); - qDebug("-> %s", retval.constData()); - -#endif - - QCodeNode *fct = getNode(); - fct->line = line; - fct->roles = QByteArray("f@") + name + "@" + retval + - "@" + QByteArray::number(visibility) + "@"; - - // if ( l ) qDebug("function at line %i", line); - - // templates - - if (ltemplates.count()) - fct->roles += ::join(ltemplates, "$"); - - fct->roles += - QByteArray("@") + QByteArray::number(fq) + "@"; - - foreach (const QByteArray &a, args) - fct->roles += a + ", "; - - if (args.count()) - fct->roles.chop(2); - - if (bNeedCxt) - fct->roles += "@" + sContext; - - fct->attach(pScope); - } - - ltemplates.clear(); - buffer_unused.clear(); - - } else { - buffer_unused << token; - } - } else { - buffer_unused << token; - } - - ++id; - break; - } - } - } -} - -/* - full table kept for evolutivity but only directly parsed keyword - have to be "visible"... -*/ -static const QLatin1String KeywordTable[] = { - // keyword - /* - QLatin1String("__attribute__"), - QLatin1String("asm"), - QLatin1String("auto"), - QLatin1String("bool"), - QLatin1String("break"), - QLatin1String("case"), - QLatin1String("catch"), - QLatin1String("char"), - */ - QLatin1String("class"), - - /* - QLatin1String("const"), - QLatin1String("continue"), - QLatin1String("do"), - QLatin1String("default"), - QLatin1String("delete"), - QLatin1String("double"), - QLatin1String("else"), - */ - - QLatin1String("enum"), - - // QLatin1String("explicit"), - - QLatin1String("extern"), - - /* - QLatin1String("float"), - QLatin1String("for"), - */ - - QLatin1String("friend"), - - /* - QLatin1String("goto"), - QLatin1String("if"), - QLatin1String("inline"), - QLatin1String("int"), - QLatin1String("long"), - QLatin1String("mutable"), - */ - - QLatin1String("namespace"), - - /* - QLatin1String("new"), - QLatin1String("operator"), - QLatin1String("private"), - QLatin1String("protected"), - QLatin1String("public"), - QLatin1String("register"), - QLatin1String("return"), - QLatin1String("short"), - QLatin1String("signed"), - QLatin1String("static"), - */ - - QLatin1String("struct"), - - /* - QLatin1String("switch"), - QLatin1String("sizeof"), - */ - - QLatin1String("template"), - - /* - QLatin1String("this"), - QLatin1String("throw"), - QLatin1String("try"), - */ - - QLatin1String("typedef"), - - // QLatin1String("typename"), - - QLatin1String("union"), - - // QLatin1String("unsigned"), - QLatin1String("using") - - /* - , - QLatin1String("virtual"), - QLatin1String("void"), - QLatin1String("volatile"), - QLatin1String("wchar_t"), - QLatin1String("while") - */ -}; - -static const QAsParser::KeywordId IdTable[] = { - // keyword ID - /* - QCppParser::KEYWORD_ATTRIBUTE, - QCppParser::KEYWORD_ASM, - QCppParser::KEYWORD_AUTO, - QCppParser::KEYWORD_BOOL, - QCppParser::KEYWORD_BREAK, - QCppParser::KEYWORD_CASE, - QCppParser::KEYWORD_CATCH, - QCppParser::KEYWORD_CHAR, - */ - - QAsParser::KEYWORD_CLASS, - - /* - QCppParser::KEYWORD_CONST, - QCppParser::KEYWORD_CONTINUE, - QCppParser::KEYWORD_DO, - QCppParser::KEYWORD_DEFAULT, - QCppParser::KEYWORD_DELETE, - QCppParser::KEYWORD_DOUBLE, - QCppParser::KEYWORD_ELSE, - */ - - QAsParser::KEYWORD_ENUM, - - // QCppParser::KEYWORD_EXPLICIT, - - QAsParser::KEYWORD_EXTERN, - - /* - QCppParser::KEYWORD_FLOAT, - QCppParser::KEYWORD_FOR, - */ - - QAsParser::KEYWORD_FRIEND, - - /* - QCppParser::KEYWORD_GOTO, - QCppParser::KEYWORD_IF, - QCppParser::KEYWORD_INLINE, - QCppParser::KEYWORD_INT, - QCppParser::KEYWORD_LONG, - QCppParser::KEYWORD_MUTABLE, - */ - - QAsParser::KEYWORD_NAMESPACE, - - /* - QCppParser::KEYWORD_NEW, - QCppParser::KEYWORD_OPERATOR, - QCppParser::KEYWORD_PRIVATE, - QCppParser::KEYWORD_PROTECTED, - QCppParser::KEYWORD_PUBLIC, - QCppParser::KEYWORD_REGISTER, - QCppParser::KEYWORD_RETURN, - QCppParser::KEYWORD_SHORT, - QCppParser::KEYWORD_SIGNED, - QAsParser::KEYWORD_STRUCT, - */ - - /* - QCppParser::KEYWORD_SWITCH, - QCppParser::KEYWORD_SIZEOF, - */ - - QAsParser::KEYWORD_TEMPLATE, - - /* - QCppParser::KEYWORD_THIS, - QCppParser::KEYWORD_THROW, - QCppParser::KEYWORD_TRY, - */ - - QAsParser::KEYWORD_TYPEDEF, - - // QCppParser::KEYWORD_TYPENAME, - - // QCppParser::KEYWORD_UNSIGNED, - - QAsParser::KEYWORD_USING, - - /* - QCppParser::KEYWORD_VIRTUAL, - QCppParser::KEYWORD_VOID, - QCppParser::KEYWORD_VOLATILE, - QCppParser::KEYWORD_WCHAR_T, - QCppParser::KEYWORD_WHILE - */ -}; - -Q_DECL_UNUSED static const int ids = sizeof(IdTable) / sizeof(IdTable[0]); - -static const int keywords = sizeof(KeywordTable) / sizeof(KeywordTable[0]); - -static const QLatin1String *invalid_match = KeywordTable + keywords; - -static QAsParser::KeywordId keyword(const char *s) { - // if ( keywords != ids ) - // qFatal("QCodeParser::update() : misconstructed keyword hash..."); - - const QLatin1String *match = - std::lower_bound(KeywordTable, invalid_match, s); - - return (match == invalid_match) ? QAsParser::KEYWORD_NONE - : IdTable[match - KeywordTable]; -} diff --git a/src/class/qasparser.h b/src/class/qasparser.h index 1dfc08f..f8de188 100644 --- a/src/class/qasparser.h +++ b/src/class/qasparser.h @@ -1,87 +1,13 @@ #ifndef _QAS_PARSER_H_ #define _QAS_PARSER_H_ -#include "qcodelexer.h" -#include "qcodeparser.h" +#include -#include - -class QAsParser : public QCodeParser { +class QAsParser : public QObject { + Q_OBJECT public: - enum KeywordId { - KEYWORD_NONE = -1, - - KEYWORD_ATTRIBUTE, - KEYWORD_AUTO, - KEYWORD_BOOL, - KEYWORD_BREAK, - KEYWORD_CASE, - KEYWORD_CATCH, - KEYWORD_CHAR, - KEYWORD_CLASS, - KEYWORD_CONST, - KEYWORD_CONTINUE, - KEYWORD_DEFAULT, - KEYWORD_DELETE, - KEYWORD_DO, - KEYWORD_DOUBLE, - KEYWORD_ELSE, - KEYWORD_ENUM, - KEYWORD_EXPLICIT, - KEYWORD_EXTERN, - KEYWORD_FLOAT, - KEYWORD_FOR, - KEYWORD_FRIEND, - KEYWORD_FUNCTION, - KEYWORD_GOTO, - KEYWORD_IF, - KEYWORD_INLINE, - KEYWORD_INT, - KEYWORD_INTERNAL, - KEYWORD_LONG, - KEYWORD_NAMESPACE, - KEYWORD_NEW, - KEYWORD_OPERATOR, - KEYWORD_PRIVATE, - KEYWORD_PROTECTED, - KEYWORD_PUBLIC, - KEYWORD_RETURN, - KEYWORD_SHORT, - KEYWORD_SIGNED, - KEYWORD_STATIC, - KEYWORD_SWITCH, - KEYWORD_SIZEOF, - KEYWORD_TEMPLATE, - KEYWORD_THIS, - KEYWORD_THROW, - KEYWORD_TRY, - KEYWORD_TYPEDEF, - KEYWORD_TYPENAME, - KEYWORD_UNSIGNED, - KEYWORD_USING, - KEYWORD_VIRTUAL, - KEYWORD_VOID, - KEYWORD_WHILE, - - KEYWORD_COUNT - }; - - QAsParser(); + explicit QAsParser(QObject *parent = nullptr); virtual ~QAsParser(); - - virtual QCodeLexer *lexer(QCodeStream *s); - - virtual QString language() const; - virtual bool canParse(const QString &fn) const; - virtual void update(QCodeNode *n, QCodeLexer *src, bool check = true); - - inline QCodeNode *getNode() { return QCodeParser::getNode(); } - - void update(QCodeNode *n, QCodeLexer *l, QTokenList &tokens, int id, - int end, bool bNeedCxt = true, QTokenList *ns = 0); - -private: - QString sContext; }; #endif // !_QCPP_PARSER_H_ diff --git a/src/class/setting.h b/src/class/setting.h deleted file mode 100644 index 7e6cb6c..0000000 --- a/src/class/setting.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef SETTING_H -#define SETTING_H - -#include -#include - -#define HANDLE_CONFIG \ - QSettings set(QStringLiteral(APP_ORG), QStringLiteral(APP_NAME)) - -#define CONFIG set - -#define WRITE_CONFIG(config, dvalue) set.setValue(config, dvalue) - -#define READ_CONFIG(config, dvalue) set.value(config, dvalue) - -#define READ_CONFIG_SAFE(var, config, dvalue, func) \ - { \ - auto b = false; \ - var = READ_CONFIG(config, dvalue).func(&b); \ - if (!b) { \ - var = dvalue; \ - } \ - } - -#define READ_CONFIG_INT(var, config, dvalue) \ - READ_CONFIG_SAFE(var, config, dvalue, toInt) - -#define READ_CONFIG_BOOL(var, config, dvalue) \ - var = READ_CONFIG(config, dvalue).toBool() - -#define READ_CONFIG_QSIZETYPE(var, config, dvalue) \ - READ_CONFIG_SAFE(var, config, dvalue, toLongLong) - -#define READ_CONFIG_INT_POSITIVE(var, config, dvalue) \ - { \ - Q_ASSERT(dvalue > 0); \ - READ_CONFIG_SAFE(var, config, dvalue, toInt); \ - if (var <= 0) { \ - var = dvalue; \ - } \ - } - -#define READ_CONFIG_DOUBLE_POSITIVE(var, config, dvalue) \ - { \ - Q_ASSERT(dvalue > 0); \ - READ_CONFIG_SAFE(var, config, dvalue, toDouble); \ - if (var <= 0) { \ - var = dvalue; \ - } \ - } - -#endif // SETTING_H diff --git a/src/class/settingmanager.cpp b/src/class/settingmanager.cpp index d286634..cdce5a5 100644 --- a/src/class/settingmanager.cpp +++ b/src/class/settingmanager.cpp @@ -1,11 +1,60 @@ #include "settingmanager.h" -#include "setting.h" #include "class/logger.h" #include "class/skinmanager.h" #include "utilities.h" #include #include +#include + +#define HANDLE_CONFIG \ + QSettings set(QStringLiteral(APP_ORG), QStringLiteral(APP_NAME)) + +#define CONFIG set + +#define WRITE_CONFIG(config, dvalue) \ + if (this->_setUnsaved.testFlag(SETTING_ITEM::config)) { \ + set.setValue(config, dvalue); \ + _setUnsaved.setFlag(SettingManager::SETTING_ITEM::config, false); \ + } + +#define READ_CONFIG(config, dvalue) set.value(config, dvalue) + +#define READ_CONFIG_SAFE(var, config, dvalue, func) \ + { \ + auto b = false; \ + var = READ_CONFIG(config, dvalue).func(&b); \ + if (!b) { \ + var = dvalue; \ + } \ + } + +#define READ_CONFIG_INT(var, config, dvalue) \ + READ_CONFIG_SAFE(var, config, dvalue, toInt) + +#define READ_CONFIG_BOOL(var, config, dvalue) \ + var = READ_CONFIG(config, dvalue).toBool() + +#define READ_CONFIG_QSIZETYPE(var, config, dvalue) \ + READ_CONFIG_SAFE(var, config, dvalue, toLongLong) + +#define READ_CONFIG_INT_POSITIVE(var, config, dvalue) \ + { \ + Q_ASSERT(dvalue > 0); \ + READ_CONFIG_SAFE(var, config, dvalue, toInt); \ + if (var <= 0) { \ + var = dvalue; \ + } \ + } + +#define READ_CONFIG_DOUBLE_POSITIVE(var, config, dvalue) \ + { \ + Q_ASSERT(dvalue > 0); \ + READ_CONFIG_SAFE(var, config, dvalue, toDouble); \ + if (var <= 0) { \ + var = dvalue; \ + } \ + } const auto DOCK_LAYOUT = QStringLiteral("dock.layout"); const auto SCRIPT_DOCK_LAYOUT = QStringLiteral("script.layout"); @@ -127,8 +176,6 @@ void SettingManager::load() { } } - emit sigAppFontFamilyChanged(m_appFontFamily); - emit sigAppfontSizeChanged(m_appfontSize); emit sigEditorfontSizeChanged(m_editorfontSize); emit sigCopylimitChanged(m_copylimit); emit sigDecodeStrlimitChanged(m_decodeStrlimit); @@ -159,25 +206,42 @@ bool SettingManager::allowUsrScriptInRoot() const { } void SettingManager::setAllowUsrScriptInRoot(bool newAllowUsrScriptInRoot) { - m_allowUsrScriptInRoot = newAllowUsrScriptInRoot; + if (m_allowUsrScriptInRoot != newAllowUsrScriptInRoot) { + m_allowUsrScriptInRoot = newAllowUsrScriptInRoot; + _setUnsaved.setFlag(SETTING_ITEM::SCRIPT_ALLOW_USRSCRIPT_INROOT); + } } void SettingManager::setUsrHideCats(const QStringList &newUsrHideCats) { - m_usrHideCats = newUsrHideCats; + if (m_usrHideCats != newUsrHideCats) { + m_usrHideCats = newUsrHideCats; + _setUnsaved.setFlag(SETTING_ITEM::SCRIPT_USRHIDECATS); + } } void SettingManager::setSysHideCats(const QStringList &newSysHideCats) { - m_sysHideCats = newSysHideCats; + if (m_sysHideCats != newSysHideCats) { + m_sysHideCats = newSysHideCats; + _setUnsaved.setFlag(SETTING_ITEM::SCRIPT_SYSHIDECATS); + } } int SettingManager::logLevel() const { return m_logLevel; } -void SettingManager::setLogLevel(int newLogLevel) { m_logLevel = newLogLevel; } +void SettingManager::setLogLevel(int newLogLevel) { + if (m_logLevel != newLogLevel) { + m_logLevel = newLogLevel; + _setUnsaved.setFlag(SETTING_ITEM::OTHER_LOG_LEVEL); + } +} bool SettingManager::useNativeTitleBar() const { return m_useNativeTitleBar; } void SettingManager::setUseNativeTitleBar(bool newUseNativeTitleBar) { - m_useNativeTitleBar = newUseNativeTitleBar; + if (m_useNativeTitleBar != newUseNativeTitleBar) { + m_useNativeTitleBar = newUseNativeTitleBar; + _setUnsaved.setFlag(SETTING_ITEM::OTHER_USE_NATIVE_TITLEBAR); + } } bool SettingManager::useNativeFileDialog() const { @@ -185,7 +249,10 @@ bool SettingManager::useNativeFileDialog() const { } void SettingManager::setUseNativeFileDialog(bool newUseNativeFileDialog) { - m_useNativeFileDialog = newUseNativeFileDialog; + if (m_useNativeFileDialog != newUseNativeFileDialog) { + m_useNativeFileDialog = newUseNativeFileDialog; + _setUnsaved.setFlag(SETTING_ITEM::OTHER_USESYS_FILEDIALOG); + } } QByteArray SettingManager::scriptDockLayout() const { @@ -194,7 +261,10 @@ QByteArray SettingManager::scriptDockLayout() const { void SettingManager::setScriptDockLayout( const QByteArray &newScriptDockLayout) { - m_scriptDockLayout = newScriptDockLayout; + if (m_scriptDockLayout != newScriptDockLayout) { + m_scriptDockLayout = newScriptDockLayout; + _setUnsaved.setFlag(SETTING_ITEM::SCRIPT_DOCK_LAYOUT); + } } QStringList SettingManager::sysHideCats() const { return m_sysHideCats; } @@ -207,7 +277,10 @@ QList SettingManager::recentScriptFiles() const { void SettingManager::setRecentScriptFiles( const QList &newRecentScriptFiles) { - m_recentScriptFiles = newRecentScriptFiles; + if (m_recentScriptFiles != newRecentScriptFiles) { + m_recentScriptFiles = newRecentScriptFiles; + _setUnsaved.setFlag(SETTING_ITEM::SCRIPT_RECENTFILES); + } } QString SettingManager::appFontFamily() const { return m_appFontFamily; } @@ -215,20 +288,26 @@ QString SettingManager::appFontFamily() const { return m_appFontFamily; } void SettingManager::setAppFontFamily(const QString &newAppFontFamily) { if (m_appFontFamily != newAppFontFamily) { m_appFontFamily = newAppFontFamily; - emit sigAppFontFamilyChanged(newAppFontFamily); + _setUnsaved.setFlag(SETTING_ITEM::APP_FONTFAMILY); } } bool SettingManager::editorShowHeader() const { return m_editorShowHeader; } void SettingManager::setEditorShowHeader(bool newEditorShowAddr) { - m_editorShowHeader = newEditorShowAddr; + if (m_editorShowHeader != newEditorShowAddr) { + m_editorShowHeader = newEditorShowAddr; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_SHOW_ADDR); + } } bool SettingManager::enablePlugin() const { return m_enablePlugin; } void SettingManager::setEnablePlugin(bool newEnablePlugin) { - m_enablePlugin = newEnablePlugin; + if (m_enablePlugin != newEnablePlugin) { + m_enablePlugin = newEnablePlugin; + _setUnsaved.setFlag(SETTING_ITEM::PLUGIN_ENABLE); + } } QList SettingManager::recentHexFiles() const { @@ -237,7 +316,10 @@ QList SettingManager::recentHexFiles() const { void SettingManager::setRecentFiles( const QList &newRecentFiles) { - m_recentHexFiles = newRecentFiles; + if (m_recentHexFiles != newRecentFiles) { + m_recentHexFiles = newRecentFiles; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_RECENTFILES); + } } Qt::WindowState SettingManager::defaultWinState() const { @@ -254,7 +336,10 @@ void SettingManager::setDefaultWinState(Qt::WindowState newDefaultWinState) { newDefaultWinState = Qt::WindowMaximized; break; } - m_defaultWinState = newDefaultWinState; + if (m_defaultWinState != newDefaultWinState) { + m_defaultWinState = newDefaultWinState; + _setUnsaved.setFlag(SETTING_ITEM::APP_WINDOWSIZE); + } } void SettingManager::save(SETTINGS cat) { @@ -339,9 +424,11 @@ void SettingManager::reset(SETTINGS cat) { qsizetype SettingManager::decodeStrlimit() const { return m_decodeStrlimit; } void SettingManager::setDecodeStrlimit(qsizetype newDecodeStrlimit) { + newDecodeStrlimit = + qBound(qsizetype(100), newDecodeStrlimit, qsizetype(1024)); if (m_decodeStrlimit != newDecodeStrlimit) { - m_decodeStrlimit = - qBound(qsizetype(100), newDecodeStrlimit, qsizetype(1024)); + m_decodeStrlimit = newDecodeStrlimit; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_DECSTRLIMIT); emit sigDecodeStrlimitChanged(m_decodeStrlimit); } } @@ -349,8 +436,10 @@ void SettingManager::setDecodeStrlimit(qsizetype newDecodeStrlimit) { qsizetype SettingManager::copylimit() const { return m_copylimit; } void SettingManager::setCopylimit(qsizetype newCopylimit) { + newCopylimit = qBound(qsizetype(100), newCopylimit, qsizetype(1024)); if (m_copylimit != newCopylimit) { - m_copylimit = qBound(qsizetype(100), newCopylimit, qsizetype(1024)); + m_copylimit = newCopylimit; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_COPY_LIMIT); emit sigDecodeStrlimitChanged(m_copylimit); } } @@ -358,19 +447,28 @@ void SettingManager::setCopylimit(qsizetype newCopylimit) { QString SettingManager::editorEncoding() const { return m_editorEncoding; } void SettingManager::setEditorEncoding(const QString &newEditorEncoding) { - m_editorEncoding = newEditorEncoding; + if (m_editorEncoding != newEditorEncoding) { + m_editorEncoding = newEditorEncoding; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_ENCODING); + } } bool SettingManager::editorShowtext() const { return m_editorShowtext; } void SettingManager::setEditorShowtext(bool newEditorShowtext) { - m_editorShowtext = newEditorShowtext; + if (m_editorShowtext != newEditorShowtext) { + m_editorShowtext = newEditorShowtext; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_SHOW_TEXT); + } } bool SettingManager::editorShowcol() const { return m_editorShowcol; } void SettingManager::setEditorShowcol(bool newEditorShowcol) { - m_editorShowcol = newEditorShowcol; + if (m_editorShowcol != newEditorShowcol) { + m_editorShowcol = newEditorShowcol; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_SHOW_COL); + } } int SettingManager::editorfontSize() const { return m_editorfontSize; } @@ -378,6 +476,7 @@ int SettingManager::editorfontSize() const { return m_editorfontSize; } void SettingManager::setEditorfontSize(int newEditorfontSize) { if (m_editorfontSize != newEditorfontSize) { m_editorfontSize = newEditorfontSize; + _setUnsaved.setFlag(SETTING_ITEM::EDITOR_FONTSIZE); emit sigEditorfontSizeChanged(newEditorfontSize); } } @@ -387,20 +486,26 @@ int SettingManager::appfontSize() const { return m_appfontSize; } void SettingManager::setAppfontSize(int newAppfontSize) { if (m_appfontSize != newAppfontSize) { m_appfontSize = newAppfontSize; - emit sigAppfontSizeChanged(newAppfontSize); + _setUnsaved.setFlag(SETTING_ITEM::APP_FONTSIZE); } } bool SettingManager::enablePlgInRoot() const { return m_enablePlgInRoot; } void SettingManager::setEnablePlgInRoot(bool newEnablePlgInRoot) { - m_enablePlgInRoot = newEnablePlgInRoot; + if (m_enablePlgInRoot != newEnablePlgInRoot) { + m_enablePlgInRoot = newEnablePlgInRoot; + _setUnsaved.setFlag(SETTING_ITEM::PLUGIN_ENABLE_ROOT); + } } QString SettingManager::defaultLang() const { return m_defaultLang; } void SettingManager::setDefaultLang(const QString &newDefaultLang) { - m_defaultLang = newDefaultLang; + if (m_defaultLang != newDefaultLang) { + m_defaultLang = newDefaultLang; + _setUnsaved.setFlag(SETTING_ITEM::APP_LANGUAGE); + } } SettingManager &SettingManager::instance() { @@ -413,9 +518,17 @@ SettingManager::~SettingManager() {} QByteArray SettingManager::dockLayout() const { return m_dockLayout; } void SettingManager::setDockLayout(const QByteArray &newDockLayout) { - m_dockLayout = newDockLayout; + if (m_dockLayout != newDockLayout) { + m_dockLayout = newDockLayout; + _setUnsaved.setFlag(SETTING_ITEM::DOCK_LAYOUT); + } } int SettingManager::themeID() const { return m_themeID; } -void SettingManager::setThemeID(int newThemeID) { m_themeID = newThemeID; } +void SettingManager::setThemeID(int newThemeID) { + if (m_themeID != newThemeID) { + m_themeID = newThemeID; + _setUnsaved.setFlag(SETTING_ITEM::SKIN_THEME); + } +} diff --git a/src/class/settingmanager.h b/src/class/settingmanager.h index 7a43429..4a5b43b 100644 --- a/src/class/settingmanager.h +++ b/src/class/settingmanager.h @@ -23,6 +23,40 @@ public: ALL = APP | PLUGIN | EDITOR | SCRIPT | OTHER }; Q_DECLARE_FLAGS(SETTINGS, SETTING) +private: + // Flags to indicate whether the modification has been made. + // There are a maximum of 32 flags, + // but it is impossible to have more than this. + enum class SETTING_ITEM : quint32 { + DOCK_LAYOUT = 1u, + SCRIPT_DOCK_LAYOUT = 1u << 1, + APP_LASTUSED_PATH = 1u << 2, + SKIN_THEME = 1u << 3, + APP_FONTFAMILY = 1u << 4, + APP_FONTSIZE = 1u << 5, + APP_WINDOWSIZE = 1u << 6, + APP_LANGUAGE = 1u << 7, + PLUGIN_ENABLE = 1u << 8, + PLUGIN_ENABLE_ROOT = 1u << 9, + EDITOR_FONTSIZE = 1u << 10, + EDITOR_SHOW_ADDR = 1u << 11, + EDITOR_SHOW_COL = 1u << 12, + EDITOR_SHOW_TEXT = 1u << 13, + EDITOR_ENCODING = 1u << 14, + EDITOR_FIND_MAXCOUNT = 1u << 15, + EDITOR_COPY_LIMIT = 1u << 16, + EDITOR_DECSTRLIMIT = 1u << 17, + EDITOR_RECENTFILES = 1u << 18, + SCRIPT_RECENTFILES = 1u << 19, + SCRIPT_ALLOW_USRSCRIPT_INROOT = 1u << 20, + SCRIPT_USRHIDECATS = 1u << 21, + SCRIPT_SYSHIDECATS = 1u << 22, + OTHER_USESYS_FILEDIALOG = 1u << 23, + OTHER_USE_NATIVE_TITLEBAR = 1u << 24, + OTHER_LOG_LEVEL = 1u << 25 + }; + Q_DECLARE_FLAGS(SETTING_ITEMS, SETTING_ITEM) + public: static SettingManager &instance(); @@ -113,9 +147,6 @@ signals: void sigDecodeStrlimitChanged(int v); void sigCopylimitChanged(int v); - void sigAppfontSizeChanged(int v); - void sigAppFontFamilyChanged(const QString &font); - void logLevelChanged(); private: @@ -164,6 +195,7 @@ private: private: QFont _defaultFont; + SETTING_ITEMS _setUnsaved; }; #endif // SETTINGMANAGER_H diff --git a/3rdparty/qcodemodel2/qcm-config.h b/src/codemodel/qcm-config.h similarity index 70% rename from 3rdparty/qcodemodel2/qcm-config.h rename to src/codemodel/qcm-config.h index b52bc87..94ab63f 100644 --- a/3rdparty/qcodemodel2/qcm-config.h +++ b/src/codemodel/qcm-config.h @@ -18,21 +18,8 @@ #include -/*! - \macro QCM_EXPORT - Allow a cross-platform and sure possibility to link in static or dynamic - way, depending to what's needed... -*/ -#ifdef _QCODE_MODEL_BUILD_DLL_ -#if (defined(QT_SHARED) || defined(QT_DLL)) && !defined(QT_PLUGIN) -#define QCM_EXPORT Q_DECL_EXPORT -#endif -#else -#ifdef _QCODE_MODEL_BUILD_STATIC_ +#ifndef QCM_EXPORT #define QCM_EXPORT -#else -#define QCM_EXPORT Q_DECL_IMPORT -#endif #endif class QByteArray; diff --git a/3rdparty/qcodemodel2/qcodemodel.cpp b/src/codemodel/qcodemodel.cpp similarity index 85% rename from 3rdparty/qcodemodel2/qcodemodel.cpp rename to src/codemodel/qcodemodel.cpp index 36e6cd1..7e55dfb 100644 --- a/3rdparty/qcodemodel2/qcodemodel.cpp +++ b/src/codemodel/qcodemodel.cpp @@ -20,9 +20,7 @@ \brief Implementation of the QCodeModel class. */ -#include "qcodeloader.h" #include "qcodenode.h" -#include "qcodeparser.h" #define Q_EXTRACT_INDEX(i, d) \ QCodeNode *d = static_cast(i.internalPointer()); @@ -60,7 +58,7 @@ void QCodeModel::q_uncache(QCodeNode *n, QByteArray cxt = QByteArray()) { /*! \brief ctor */ -QCodeModel::QCodeModel(QObject *p) : QAbstractItemModel(p), m_loader(0) {} +QCodeModel::QCodeModel(QObject *p) : QAbstractItemModel(p) {} /*! \brief dtor @@ -73,67 +71,6 @@ QCodeModel::~QCodeModel() { clearTopLevelNodes(); } */ QList QCodeModel::topLevelNodes() const { return m_topLevel; } -/*! - \return The current code loader used by this model -*/ -QCodeLoader *QCodeModel::codeLoader() const { return m_loader; } - -/*! - \brief Set the code loader used by this model -*/ -void QCodeModel::setCodeLoader(QCodeLoader *p) { m_loader = p; } - -/*! - \brief Update a file within a group - \param group group of files to remove (as passed to addGroup()) - \param file file to update -*/ -void QCodeModel::updateGroup(const QString &group, const QString &file) { - QByteArray grp = group.toLocal8Bit(); - - foreach (QCodeNode *n, m_topLevel) { - // qDebug("group %s ?", n->context().constData()); - - if (n->role(QCodeNode::Context) == grp) { - m_loader->update(n, file); - return; - } - } - - // qDebug("group %s not found", qPrintable(group)); -} - -/*! - \brief Add a group of files of whathever type (typically from a project) - \param group group of files to add - \param files list of files to load to populate the tree -*/ -void QCodeModel::addGroup(const QString &group, const QStringList &files) { - if (!m_loader) - return; - - foreach (QCodeNode *n, m_topLevel) - if (n->context() == group) - return; - - // qDebug("loading %i files into group %s", files.count(), - // qPrintable(group)); - m_loader->load(group, files, this); -} - -/*! - \brief Remove a group of files from the model - \param group group of files to remove (as passed to addGroup()) -*/ -void QCodeModel::removeGroup(const QString &group) { - foreach (QCodeNode *n, m_topLevel) { - if (n->role(QCodeNode::Context) == group) { - removeTopLevelNode(n); - delete n; - } - } -} - /*! \brief Please read Qt docs on Model/View framework for more informations */ @@ -343,7 +280,8 @@ bool QCodeModel::isCachable(QCodeNode *n, QByteArray &cxt) const { cxt += qn; return true; - } else if ((t == QCodeNode::Enum) || (t == QCodeNode::Class) || + } else if ((t == QCodeNode::Enum) || (t == QCodeNode::Union) || + (t == QCodeNode::Class) || (t == QCodeNode::Struct) || (t == QCodeNode::Typedef)) { cxt += qn; diff --git a/3rdparty/qcodemodel2/qcodemodel.h b/src/codemodel/qcodemodel.h similarity index 89% rename from 3rdparty/qcodemodel2/qcodemodel.h rename to src/codemodel/qcodemodel.h index e8c29f5..18b29b5 100644 --- a/3rdparty/qcodemodel2/qcodemodel.h +++ b/src/codemodel/qcodemodel.h @@ -23,8 +23,6 @@ #include struct QCodeNode; -class QCodeParser; -class QCodeLoader; class QCM_EXPORT QCodeModel : public QAbstractItemModel { Q_OBJECT @@ -64,14 +62,6 @@ public: virtual bool isCachable(QCodeNode *n, QByteArray &cxt) const; - QCodeLoader *codeLoader() const; - void setCodeLoader(QCodeLoader *p); - -public slots: - void updateGroup(const QString &group, const QString &file); - void addGroup(const QString &group, const QStringList &files); - void removeGroup(const QString &group); - protected: void beginInsertRows(const QModelIndex idx, int beg, int end); void beginRemoveRows(const QModelIndex idx, int beg, int end); @@ -94,8 +84,6 @@ private: QList m_topLevel; - QCodeLoader *m_loader; - QStack m_cache_ops; QHash m_cache; }; diff --git a/3rdparty/qcodemodel2/qcodenode.cpp b/src/codemodel/qcodenode.cpp similarity index 86% rename from 3rdparty/qcodemodel2/qcodenode.cpp rename to src/codemodel/qcodenode.cpp index f3faa2d..acdc8d4 100644 --- a/3rdparty/qcodemodel2/qcodenode.cpp +++ b/src/codemodel/qcodenode.cpp @@ -23,10 +23,17 @@ #include "qsourcecodewatcher.h" +/* + + + +*/ enum CacheIndex { ICON_ENUM, ICON_ENUMERATOR, + ICON_UNION, ICON_CLASS, + ICON_STRUCT, ICON_TYPEDEF, ICON_NAMESPACE, ICON_FUNCTION = ICON_NAMESPACE + 2, @@ -39,11 +46,15 @@ static QIcon icon(int cacheIndex) { static bool setup = false; if (!setup) { + q_icon_cache[ICON_UNION] = QIcon(":/completion/CVunion.png"); + q_icon_cache[ICON_ENUM] = QIcon(":/completion/CVenum.png"); q_icon_cache[ICON_ENUMERATOR] = QIcon(":/completion/CVenumerator.png"); q_icon_cache[ICON_CLASS] = QIcon(":/completion/CVclass.png"); + q_icon_cache[ICON_STRUCT] = QIcon(":/completion/CVstruct.png"); + q_icon_cache[ICON_TYPEDEF] = QIcon(":/completion/CVtypedef.png"); q_icon_cache[ICON_NAMESPACE] = QIcon(":/completion/CVnamespace.png"); @@ -60,6 +71,9 @@ static QIcon icon(int cacheIndex) { q_icon_cache[ICON_FUNCTION + QCodeNode::VISIBILITY_PRIVATE] = QIcon(":/completion/CVprivate_meth.png"); + q_icon_cache[ICON_FUNCTION + QCodeNode::VISIBILITY_SIGNAL] = + QIcon(":/completion/CVprotected_signal.png"); + q_icon_cache[ICON_VARIABLE + QCodeNode::VISIBILITY_DEFAULT] = QIcon(":/completion/CVglobal_var.png"); @@ -349,12 +363,27 @@ QVariant QCodeNode::data(int r) const { return d; } + case Struct: { + QByteArray d("struct "); + d += role(Name); + + QByteArray a = role(Ancestors); + + if (a.length()) + d += " : " + a; + + return d; + } + case Enum: return QByteArray("enum ") + role(Name); case Enumerator: return role(Name) + " = " + role(Value); + case Union: + return QByteArray("union ") + role(Name); + case Namespace: return QByteArray("namespace ") + role(Name); @@ -382,12 +411,20 @@ QVariant QCodeNode::data(int r) const { // storage class if (m_specifiers & QCodeNode::SPECIFIER_AUTO) specifier += " auto "; + else if (m_specifiers & QCodeNode::SPECIFIER_REGISTER) + specifier += " register "; + else if (m_specifiers & QCodeNode::SPECIFIER_STATIC) + specifier += " static "; else if (m_specifiers & QCodeNode::SPECIFIER_EXTERN) specifier += " extern "; + else if (m_specifiers & QCodeNode::SPECIFIER_MUTABLE) + specifier += " mutable "; // cv qualifier (for class members) if (m_specifiers & QCodeNode::SPECIFIER_CONST) specifier += " const "; + else if (m_specifiers & QCodeNode::SPECIFIER_VOLATILE) + specifier += " volatile "; if (specifier.length()) signature += " [" + specifier.simplified() + "]"; @@ -412,6 +449,17 @@ QVariant QCodeNode::data(int r) const { if (m_qualifiers & QCodeNode::QUALIFIER_CONST) qualifier += " const "; + else if (m_qualifiers & QCodeNode::QUALIFIER_VOLATILE) + qualifier += " volatile "; + else if (m_qualifiers & QCodeNode::QUALIFIER_STATIC) + qualifier += " static "; + + if (m_qualifiers & QCodeNode::QUALIFIER_PURE_VIRTUAL) + qualifier.prepend(" pure virtual "); + else if (m_qualifiers & QCodeNode::QUALIFIER_INLINE) + qualifier.prepend(" inline "); + else if (m_qualifiers & QCodeNode::QUALIFIER_VIRTUAL) + qualifier.prepend(" virtual "); int m_visibility = role(Visibility).toInt(); @@ -419,6 +467,8 @@ QVariant QCodeNode::data(int r) const { qualifier.prepend(" public "); else if (m_visibility == QCodeNode::VISIBILITY_PROTECTED) qualifier.prepend(" protected "); + else if (m_visibility == QCodeNode::VISIBILITY_SIGNAL) + qualifier.prepend(" signal "); else if (m_visibility == QCodeNode::VISIBILITY_PRIVATE) qualifier.prepend(" private "); else @@ -450,12 +500,18 @@ QVariant QCodeNode::data(int r) const { case Class: return icon(ICON_CLASS); + case Struct: + return icon(ICON_STRUCT); + case Enum: return icon(ICON_ENUM); case Enumerator: return icon(ICON_ENUMERATOR); + case Union: + return icon(ICON_UNION); + case Namespace: return icon(ICON_NAMESPACE); diff --git a/3rdparty/qcodemodel2/qcodenode.h b/src/codemodel/qcodenode.h similarity index 88% rename from 3rdparty/qcodemodel2/qcodenode.h rename to src/codemodel/qcodenode.h index 8e5c5a8..cb29e2a 100644 --- a/3rdparty/qcodemodel2/qcodenode.h +++ b/src/codemodel/qcodenode.h @@ -62,6 +62,7 @@ struct QCM_EXPORT QCodeNode { Language = 'l', Class = 'c', + Struct = 's', Function = 'f', @@ -70,6 +71,8 @@ struct QCM_EXPORT QCodeNode { Enum = 'e', Enumerator = 'r', + Union = 'u', + Namespace = 'n', Typedef = 't' @@ -84,6 +87,7 @@ struct QCM_EXPORT QCodeNode { enum NodeVisibility { VISIBILITY_DEFAULT = -1, VISIBILITY_PUBLIC, + VISIBILITY_SIGNAL, VISIBILITY_PROTECTED, VISIBILITY_PRIVATE }; @@ -91,7 +95,11 @@ struct QCM_EXPORT QCodeNode { enum Specifier { SPECIFIER_NONE = 0, SPECIFIER_CONST = 1, + SPECIFIER_VOLATILE = 2, + SPECIFIER_MUTABLE = 4, SPECIFIER_AUTO = 8, + SPECIFIER_STATIC = 16, + SPECIFIER_REGISTER = 32, SPECIFIER_EXTERN = 64 }; @@ -100,8 +108,12 @@ struct QCM_EXPORT QCodeNode { enum Qualifier { QUALIFIER_NONE = 0, QUALIFIER_CONST = 1, - QUALIFIER_ABSTRACT = 2, - QUALIFIER_EXTERN = 8 + QUALIFIER_VOLATILE = 2, + QUALIFIER_STATIC = 4, + QUALIFIER_EXTERN = 8, + QUALIFIER_VIRTUAL = 16, + QUALIFIER_PURE_VIRTUAL = 32, + QUALIFIER_INLINE = 64 }; typedef QFlags FunctionQualifier; diff --git a/3rdparty/qcodemodel2/qcodenodepool.cpp b/src/codemodel/qcodenodepool.cpp similarity index 100% rename from 3rdparty/qcodemodel2/qcodenodepool.cpp rename to src/codemodel/qcodenodepool.cpp diff --git a/3rdparty/qcodemodel2/qcodenodepool.h b/src/codemodel/qcodenodepool.h similarity index 100% rename from 3rdparty/qcodemodel2/qcodenodepool.h rename to src/codemodel/qcodenodepool.h diff --git a/3rdparty/qcodemodel2/qcodeproxymodel.cpp b/src/codemodel/qcodeproxymodel.cpp similarity index 97% rename from 3rdparty/qcodemodel2/qcodeproxymodel.cpp rename to src/codemodel/qcodeproxymodel.cpp index 4dc9e23..bc82b6d 100644 --- a/3rdparty/qcodemodel2/qcodeproxymodel.cpp +++ b/src/codemodel/qcodeproxymodel.cpp @@ -26,6 +26,7 @@ static QList priority = QList() << QCodeNode::Group << QCodeNode::Language << QCodeNode::Namespace << QCodeNode::Class + << QCodeNode::Struct << QCodeNode::Union << QCodeNode::Enum << QCodeNode::Typedef << QCodeNode::Function << QCodeNode::Variable; diff --git a/3rdparty/qcodemodel2/qcodebuffer.h b/src/codemodel/qcodeproxymodel.h similarity index 57% rename from 3rdparty/qcodemodel2/qcodebuffer.h rename to src/codemodel/qcodeproxymodel.h index ed8dcc3..66f4ba6 100644 --- a/3rdparty/qcodemodel2/qcodebuffer.h +++ b/src/codemodel/qcodeproxymodel.h @@ -13,31 +13,28 @@ ** ****************************************************************************/ -#ifndef _QCODE_BUFFER_H_ -#define _QCODE_BUFFER_H_ +#ifndef _QCODE_PROXY_MODEL_H_ +#define _QCODE_PROXY_MODEL_H_ -#include "qcodestream.h" +#include "qcm-config.h" /*! - \file qcodebuffer.h - \brief Definition of the QCodeBuffer class. + \file qcodeproxymodel.h + \brief Definition of the QCodeProxyModel class. */ -#include +#include + +class QCM_EXPORT QCodeProxyModel : public QSortFilterProxyModel { + Q_OBJECT -class QCM_EXPORT QCodeBuffer : public QCodeStream { public: - QCodeBuffer(const QString &s); - QCodeBuffer(const QByteArray &s); + QCodeProxyModel(QObject *p = nullptr); + virtual ~QCodeProxyModel(); - virtual char getChar(); - virtual void ungetChar(char c); - - virtual QByteArray readLine(); - -private: - int iPos; - QByteArray sBuffer; +protected: + virtual bool lessThan(const QModelIndex &left, + const QModelIndex &right) const; }; -#endif // _QCODE_BUFFER_H_ +#endif // !_QCODE_PROXY_MODEL_H_ diff --git a/3rdparty/qcodemodel2/qcodeserializer.cpp b/src/codemodel/qcodeserializer.cpp similarity index 99% rename from 3rdparty/qcodemodel2/qcodeserializer.cpp rename to src/codemodel/qcodeserializer.cpp index 1650437..c95ac23 100644 --- a/3rdparty/qcodemodel2/qcodeserializer.cpp +++ b/src/codemodel/qcodeserializer.cpp @@ -98,7 +98,9 @@ void QCodeSerializer::deserialize(QIODevice *device, bool *ok, QString *source, QCodeNode *n, *previous = 0, *parent = 0; line = device->readLine(); + auto match = header_matcher.match(line); + if (!match.hasMatch()) { qWarning("Header mismatch : %s", line.constData()); diff --git a/3rdparty/qcodemodel2/qcodeserializer.h b/src/codemodel/qcodeserializer.h similarity index 100% rename from 3rdparty/qcodemodel2/qcodeserializer.h rename to src/codemodel/qcodeserializer.h diff --git a/3rdparty/qcodemodel2/qcodeview.cpp b/src/codemodel/qcodeview.cpp similarity index 100% rename from 3rdparty/qcodemodel2/qcodeview.cpp rename to src/codemodel/qcodeview.cpp diff --git a/3rdparty/qcodemodel2/qcodeview.h b/src/codemodel/qcodeview.h similarity index 93% rename from 3rdparty/qcodemodel2/qcodeview.h rename to src/codemodel/qcodeview.h index d3efe00..4ea79b3 100644 --- a/3rdparty/qcodemodel2/qcodeview.h +++ b/src/codemodel/qcodeview.h @@ -31,8 +31,8 @@ class QCM_EXPORT QCodeView : public QTreeView { Q_OBJECT public: - QCodeView(QWidget *p = 0); - QCodeView(QCodeModel *m, QWidget *p = 0); + QCodeView(QWidget *p = nullptr); + QCodeView(QCodeModel *m, QWidget *p = nullptr); virtual ~QCodeView(); virtual void setModel(QAbstractItemModel *model); diff --git a/3rdparty/qcodemodel2/qsourcecodewatcher.cpp b/src/codemodel/qsourcecodewatcher.cpp similarity index 97% rename from 3rdparty/qcodemodel2/qsourcecodewatcher.cpp rename to src/codemodel/qsourcecodewatcher.cpp index 8504ec4..82804ac 100644 --- a/3rdparty/qcodemodel2/qsourcecodewatcher.cpp +++ b/src/codemodel/qsourcecodewatcher.cpp @@ -17,7 +17,6 @@ #include "qcodemodel.h" #include "qcodenode.h" -#include "qcodeparser.h" #include @@ -68,7 +67,8 @@ void QSourceCodeWatcher::timerEvent(QTimerEvent *e) { ++it; } else { // process - m_parser->update(m_target, it.key()); + // m_parser->update(m_target, it.key()); + // TODO it = m_state.erase(it); } } diff --git a/3rdparty/qcodemodel2/qsourcecodewatcher.h b/src/codemodel/qsourcecodewatcher.h similarity index 61% rename from 3rdparty/qcodemodel2/qsourcecodewatcher.h rename to src/codemodel/qsourcecodewatcher.h index ab21378..d4db64c 100644 --- a/3rdparty/qcodemodel2/qsourcecodewatcher.h +++ b/src/codemodel/qsourcecodewatcher.h @@ -1,17 +1,17 @@ /**************************************************************************** - ** - ** Copyright (C) 2006-2009 fullmetalcoder - ** - ** This file is part of the Edyuk project - ** - ** This file may be used under the terms of the GNU General Public License - ** version 3 as published by the Free Software Foundation and appearing in the - ** file GPL.txt included in the packaging of this file. - ** - ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - ** - ****************************************************************************/ +** +** Copyright (C) 2006-2009 fullmetalcoder +** +** This file is part of the Edyuk project +** +** This file may be used under the terms of the GNU General Public License +** version 3 as published by the Free Software Foundation and appearing in the +** file GPL.txt included in the packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ #ifndef _QSOURCE_CODE_WATCHER_H_ #define _QSOURCE_CODE_WATCHER_H_ diff --git a/src/control/qcodecompletionwidget.cpp b/src/control/qcodecompletionwidget.cpp index ccf88d7..876e3b7 100644 --- a/src/control/qcodecompletionwidget.cpp +++ b/src/control/qcodecompletionwidget.cpp @@ -22,8 +22,8 @@ #include "qdocumentline.h" #include "qeditor.h" -#include "qcodemodel.h" -#include "qcodenode.h" +#include "codemodel/qcodemodel.h" +#include "codemodel/qcodenode.h" #include #include @@ -32,7 +32,7 @@ #include QCodeCompletionWidget::QCodeCompletionWidget(QEditor *p) - : QListView(0), offset(0) { + : QListView(nullptr), offset(0) { // setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow); setBatchSize(10); setMovement(Static); diff --git a/src/control/qcodecompletionwidget.h b/src/control/qcodecompletionwidget.h index bf064cb..35507f5 100644 --- a/src/control/qcodecompletionwidget.h +++ b/src/control/qcodecompletionwidget.h @@ -19,7 +19,7 @@ #include #include -#include "qcodenode.h" +#include "codemodel/qcodenode.h" #include "qdocumentcursor.h" #include "qeditor.h" @@ -60,7 +60,7 @@ public: typedef QFlags Filter; - QCodeCompletionWidget(QEditor *p = 0); + QCodeCompletionWidget(QEditor *p = nullptr); QEditor *editor() const; void setEditor(QEditor *e); diff --git a/src/dialog/mainwindow.cpp b/src/dialog/mainwindow.cpp index f633428..873b5b5 100644 --- a/src/dialog/mainwindow.cpp +++ b/src/dialog/mainwindow.cpp @@ -1119,24 +1119,35 @@ RibbonTabContent *MainWindow::buildAboutPage(RibbonTabContent *tab) { void MainWindow::buildUpSettingDialog() { m_setdialog = new SettingDialog(this); auto generalPage = new GeneralSettingDialog(m_setdialog); + connect(generalPage, &SettingPage::optionNeedRestartChanged, m_setdialog, + &SettingDialog::toastTakeEffectReboot); m_setdialog->addPage(generalPage); auto editorPage = new EditorSettingDialog(m_setdialog); + connect(editorPage, &SettingPage::optionNeedRestartChanged, m_setdialog, + &SettingDialog::toastTakeEffectReboot); m_setdialog->addPage(editorPage); auto plgPage = new PluginSettingDialog(m_setdialog); + connect(plgPage, &SettingPage::optionNeedRestartChanged, m_setdialog, + &SettingDialog::toastTakeEffectReboot); plgPage->buildUp(m_settingPages); m_setdialog->addPage(plgPage); auto scriptPage = new ScriptSettingDialog(m_setdialog); - + connect(scriptPage, &SettingPage::optionNeedRestartChanged, m_setdialog, + &SettingDialog::toastTakeEffectReboot); m_setdialog->addPage(scriptPage); for (auto &page : m_settingPages) { if (!page->isInPluginPage()) { + connect(page, &SettingPage::optionNeedRestartChanged, m_setdialog, + &SettingDialog::toastTakeEffectReboot); m_setdialog->addPage(page); } } auto otherPage = new OtherSettingsDialog(m_setdialog); + connect(otherPage, &SettingPage::optionNeedRestartChanged, m_setdialog, + &SettingDialog::toastTakeEffectReboot); m_setdialog->addPage(otherPage); m_setdialog->build(); diff --git a/src/dialog/scriptingdialog.cpp b/src/dialog/scriptingdialog.cpp index 09eb080..f334ff7 100644 --- a/src/dialog/scriptingdialog.cpp +++ b/src/dialog/scriptingdialog.cpp @@ -12,8 +12,6 @@ #include "class/wingmessagebox.h" #include "control/toast.h" #include "qcodeeditwidget/qeditconfig.h" -#include "qcodeloader.h" -#include "qcodemodel.h" #include "qdocumentline.h" #include "qeditor.h" #include "qformatscheme.h" @@ -77,21 +75,9 @@ ScriptingDialog::ScriptingDialog(QWidget *parent) } QDocument::setDefaultFormatScheme(format); - m_codeModel = new QCodeModel(this); - m_codeModel->setCodeLoader(new QCodeLoader(this)); - - // m_codeProxy = new QCodeProxyModel(this); - // m_codeProxy->setSourceModel(m_codeModel); - // m_codeProxy->setDynamicSortFilter(true); - - // m_codeView = new QCodeView(this); - // m_codeView->setModel(m_codeProxy); - // m_codeView->setSortingEnabled(true); - // m_codeView->header()->hide(); - m_language = new QLanguageFactory(format, this); m_language->addDefinitionPath(QStringLiteral(":/qcodeedit")); - m_language->addCompletionEngine(new AsCompletion(m_codeModel, this)); + m_language->addCompletionEngine(new AsCompletion(this)); auto lmic = QLineMarksInfoCenter::instance(); lmic->loadMarkTypes(QCE::fetchDataFile(":/qcodeedit/marks.qxm")); diff --git a/src/dialog/scriptingdialog.h b/src/dialog/scriptingdialog.h index 695aea5..145bd63 100644 --- a/src/dialog/scriptingdialog.h +++ b/src/dialog/scriptingdialog.h @@ -14,8 +14,6 @@ #include "model/dbgbreakpointmodel.h" #include "model/dbgcallstackmodel.h" #include "model/dbgvarshowmodel.h" -#include "qcodeproxymodel.h" -#include "qcodeview.h" #include "qlanguagefactory.h" #include "utilities.h" @@ -235,9 +233,7 @@ private: ads::CDockManager *m_dock = nullptr; ads::CDockAreaWidget *m_editorViewArea = nullptr; QLanguageFactory *m_language = nullptr; - QCodeView *m_codeView = nullptr; - QCodeModel *m_codeModel = nullptr; - QCodeProxyModel *m_codeProxy = nullptr; + QByteArray _defaultLayout; ScriptEditor *m_curEditor = nullptr; diff --git a/src/dialog/settingdialog.cpp b/src/dialog/settingdialog.cpp index 489680b..868198a 100644 --- a/src/dialog/settingdialog.cpp +++ b/src/dialog/settingdialog.cpp @@ -2,6 +2,7 @@ #include "ui_settingdialog.h" #include "class/wingmessagebox.h" +#include "control/toast.h" #include "utilities.h" #include @@ -57,6 +58,17 @@ void SettingDialog::showConfig(int index) { _dialog->exec(); } +void SettingDialog::toastTakeEffectReboot() { + auto page = qobject_cast(sender()); + if (page) { + auto icon = page->categoryIcon(); + auto avsize = icon.availableSizes(); + Q_ASSERT(!avsize.isEmpty()); + Toast::toast(_dialog, icon.pixmap(avsize.first()), + tr("TakeEffectRestart")); + } +} + void SettingDialog::on_buttonBox_clicked(QAbstractButton *button) { auto btnbox = ui->buttonBox; if (button == btnbox->button(QDialogButtonBox::Ok)) { diff --git a/src/dialog/settingdialog.h b/src/dialog/settingdialog.h index d6d983e..e314f89 100644 --- a/src/dialog/settingdialog.h +++ b/src/dialog/settingdialog.h @@ -20,6 +20,9 @@ public: void build(); // you can only call once void showConfig(int index = -1); +public slots: + void toastTakeEffectReboot(); + private slots: void on_buttonBox_clicked(QAbstractButton *button); diff --git a/src/plugin/iwingplugin.h b/src/plugin/iwingplugin.h index 95b5c8d..84aafd5 100644 --- a/src/plugin/iwingplugin.h +++ b/src/plugin/iwingplugin.h @@ -24,7 +24,7 @@ namespace WingHex { -Q_DECL_UNUSED constexpr auto SDKVERSION = 12; +Q_DECL_UNUSED constexpr auto SDKVERSION = 13; Q_DECL_UNUSED static QString GETPLUGINQM(const QString &name) { return QCoreApplication::applicationDirPath() + diff --git a/src/plugin/settingpage.cpp b/src/plugin/settingpage.cpp deleted file mode 100644 index b206a19..0000000 --- a/src/plugin/settingpage.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "settingpage.h" - -using namespace WingHex; - -SettingPage::SettingPage(QWidget *parent) : QWidget(parent) {} diff --git a/src/plugin/settingpage.h b/src/plugin/settingpage.h index c4cf7af..25928bd 100644 --- a/src/plugin/settingpage.h +++ b/src/plugin/settingpage.h @@ -8,7 +8,10 @@ namespace WingHex { class SettingPage : public QWidget { Q_OBJECT public: - explicit SettingPage(QWidget *parent = nullptr); + explicit SettingPage(QWidget *parent = nullptr) : QWidget(parent) {} + +signals: + void optionNeedRestartChanged(); public: virtual QIcon categoryIcon() const = 0; diff --git a/src/settings/generalsettingdialog.cpp b/src/settings/generalsettingdialog.cpp index 5818517..3dbe04f 100644 --- a/src/settings/generalsettingdialog.cpp +++ b/src/settings/generalsettingdialog.cpp @@ -30,12 +30,31 @@ GeneralSettingDialog::GeneralSettingDialog(QWidget *parent) ui->lblSoftVersion->setText(WINGHEX_VERSION); ui->lblScriptVersion->setText(ANGELSCRIPT_VERSION_STRING); + Utilities::addSpecialMark(ui->lblLanguage); + Utilities::addSpecialMark(ui->lblTheme); + Utilities::addSpecialMark(ui->lblFont); + Utilities::addSpecialMark(ui->lblFontSize); + Utilities::addSpecialMark(ui->lblWinState); + + connect(ui->cbLanguage, QOverload::of(&QComboBox::currentIndexChanged), + this, &GeneralSettingDialog::optionNeedRestartChanged); + connect(ui->cbTheme, QOverload::of(&QComboBox::currentIndexChanged), + this, &GeneralSettingDialog::optionNeedRestartChanged); + connect(ui->cbFont, QOverload::of(&QComboBox::currentIndexChanged), + this, &GeneralSettingDialog::optionNeedRestartChanged); + connect(ui->sbFontSize, &QSpinBox::editingFinished, this, + &GeneralSettingDialog::optionNeedRestartChanged); + connect(ui->cbWinState, QOverload::of(&QComboBox::currentIndexChanged), + this, &GeneralSettingDialog::optionNeedRestartChanged); + reload(); } GeneralSettingDialog::~GeneralSettingDialog() { delete ui; } void GeneralSettingDialog::reload() { + this->blockSignals(true); + auto &set = SettingManager::instance(); auto langs = LanguageManager::instance().langsDisplay(); @@ -67,6 +86,8 @@ void GeneralSettingDialog::reload() { } ui->cbWinState->setCurrentIndex(s); + + this->blockSignals(false); } QIcon GeneralSettingDialog::categoryIcon() const { return ICONRES("general"); } diff --git a/src/settings/generalsettingdialog.ui b/src/settings/generalsettingdialog.ui index 22e74e5..b4ba3f1 100644 --- a/src/settings/generalsettingdialog.ui +++ b/src/settings/generalsettingdialog.ui @@ -57,7 +57,7 @@ 8 - + Language @@ -67,7 +67,7 @@ - + Theme @@ -110,7 +110,7 @@ 8 - + Font @@ -120,7 +120,7 @@ - + FontSize @@ -137,7 +137,7 @@ - + WinState diff --git a/src/settings/othersettingsdialog.cpp b/src/settings/othersettingsdialog.cpp index adeb7a1..17e1341 100644 --- a/src/settings/othersettingsdialog.cpp +++ b/src/settings/othersettingsdialog.cpp @@ -19,20 +19,28 @@ OtherSettingsDialog::OtherSettingsDialog(QWidget *parent) #ifndef WINGHEX_USE_FRAMELESS ui->cbNativeTitile->setEnabled(false); - ui->cbNativeTitile->setChecked(false); #endif + Utilities::addSpecialMark(ui->cbNativeTitile); + Utilities::addSpecialMark(ui->lblLevel); + connect(ui->cbNativeTitile, &QCheckBox::stateChanged, this, + &OtherSettingsDialog::optionNeedRestartChanged); + connect(ui->cbLogLevel, QOverload::of(&QComboBox::currentIndexChanged), + this, &OtherSettingsDialog::optionNeedRestartChanged); + reload(); } OtherSettingsDialog::~OtherSettingsDialog() { delete ui; } void OtherSettingsDialog::reload() { + this->blockSignals(true); auto &set = SettingManager::instance(); ui->cbNativeFileDialog->setChecked(set.useNativeFileDialog()); #ifdef WINGHEX_USE_FRAMELESS ui->cbNativeTitile->setChecked(set.useNativeTitleBar()); #endif + this->blockSignals(false); } QIcon OtherSettingsDialog::categoryIcon() const { return ICONRES("other"); } diff --git a/src/settings/othersettingsdialog.ui b/src/settings/othersettingsdialog.ui index dd83b3c..04057b4 100644 --- a/src/settings/othersettingsdialog.ui +++ b/src/settings/othersettingsdialog.ui @@ -59,7 +59,7 @@ - + Level diff --git a/src/settings/pluginsettingdialog.cpp b/src/settings/pluginsettingdialog.cpp index 10ce795..63688a8 100644 --- a/src/settings/pluginsettingdialog.cpp +++ b/src/settings/pluginsettingdialog.cpp @@ -1,13 +1,21 @@ #include "pluginsettingdialog.h" #include "../class/settingmanager.h" -#include "../dbghelper.h" -#include "../plugin/pluginsystem.h" -#include "../utilities.h" +#include "dbghelper.h" +#include "plugin/pluginsystem.h" #include "ui_pluginsettingdialog.h" +#include "utilities.h" PluginSettingDialog::PluginSettingDialog(QWidget *parent) : WingHex::SettingPage(parent), ui(new Ui::PluginSettingDialog) { ui->setupUi(this); + + Utilities::addSpecialMark(ui->cbEnablePlugin); + Utilities::addSpecialMark(ui->cbEnablePluginRoot); + connect(ui->cbEnablePlugin, &QCheckBox::stateChanged, this, + &PluginSettingDialog::optionNeedRestartChanged); + connect(ui->cbEnablePluginRoot, &QCheckBox::stateChanged, this, + &PluginSettingDialog::optionNeedRestartChanged); + reload(); auto &plgsys = PluginSystem::instance(); @@ -33,9 +41,11 @@ void PluginSettingDialog::buildUp(const QList &pages) { } void PluginSettingDialog::reload() { + this->blockSignals(true); auto &set = SettingManager::instance(); ui->cbEnablePlugin->setChecked(set.enablePlugin()); ui->cbEnablePluginRoot->setChecked(set.enablePlgInRoot()); + this->blockSignals(false); } QIcon PluginSettingDialog::categoryIcon() const { return ICONRES("plugin"); } diff --git a/src/settings/scriptsettingdialog.cpp b/src/settings/scriptsettingdialog.cpp index b70661a..ed03b89 100644 --- a/src/settings/scriptsettingdialog.cpp +++ b/src/settings/scriptsettingdialog.cpp @@ -9,6 +9,11 @@ ScriptSettingDialog::ScriptSettingDialog(QWidget *parent) : WingHex::SettingPage(parent), ui(new Ui::ScriptSettingDialog) { ui->setupUi(this); + + Utilities::addSpecialMark(ui->cbAllowUsrScript); + connect(ui->cbAllowUsrScript, &QCheckBox::stateChanged, this, + &ScriptSettingDialog::optionNeedRestartChanged); + loadData(); } @@ -18,7 +23,9 @@ void ScriptSettingDialog::loadData() { auto &sm = ScriptManager::instance(); auto &set = SettingManager::instance(); + this->blockSignals(true); ui->cbAllowUsrScript->setChecked(set.allowUsrScriptInRoot()); + this->blockSignals(false); auto usrCats = sm.usrScriptsDbCats(); auto hidden = set.usrHideCats(); diff --git a/src/utilities.h b/src/utilities.h index b7e4754..4b7d096 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -1,11 +1,13 @@ #ifndef UTILITIES_H #define UTILITIES_H +#include #include #include #include #include #include +#include #include #include #include @@ -215,6 +217,21 @@ public: view->verticalHeader()->setDefaultAlignment(Qt::AlignCenter); view->horizontalHeader()->setStretchLastSection(true); } + + template + static void addSpecialMark(T *w) { + if (w) { + if constexpr (std::is_same_v || + std::is_base_of_v) { + w->setText(w->text() + QStringLiteral(" (*)")); + } else if constexpr (std::is_same_v || + std::is_base_of_v) { + if (w) { + w->setText(w->text() + QStringLiteral(" (*)")); + } + } + } + } }; #endif // UTILITIES_H