diff --git a/NEWS.md b/NEWS.md index 6806c6b1..3c72a454 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +Red Panda C++ Version 2.0 + + - redesign the project parser, more efficient and correct + - enhancement: todo parser for project + Red Panda C++ Version 1.5 - fix: project files that lies in project include folder is wrongly openned in Read-only mode diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 4843163b..8a18cecc 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -1290,6 +1290,8 @@ void Editor::showEvent(QShowEvent */*event*/) } pMainWindow->debugger()->setIsForProject(inProject()); pMainWindow->bookmarkModel()->setIsForProject(inProject()); + pMainWindow->todoModel()->setIsForProject(inProject()); + // if (pSettings->codeCompletion().clearWhenEditorHidden() // && !inProject()) { // reparse(); @@ -2711,7 +2713,7 @@ void Editor::reparseTodo() { if (!highlighter()) return; - pMainWindow->todoParser()->parseFile(mFilename); + pMainWindow->todoParser()->parseFile(mFilename, inProject()); } void Editor::insertString(const QString &value, bool moveCursor) diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 4914eca3..051982c3 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -1358,6 +1358,8 @@ void MainWindow::openProject(const QString &filename, bool openFiles) mDebugger->loadForProject( changeFileExt(mProject->filename(), PROJECT_DEBUG_EXT), mProject->directory()); + mTodoModel.setIsForProject(true); + mTodoParser->parseFiles(mProject->unitFiles()); if (openFiles) { PProjectUnit unit = mProject->doAutoOpen(); @@ -4358,12 +4360,16 @@ void MainWindow::enableDebugActions() } } -void MainWindow::onTodoParseStarted(const QString&) +void MainWindow::onTodoParsingFile(const QString& filename) +{ + mTodoModel.removeTodosForFile(filename); +} +void MainWindow::onTodoParseStarted() { mTodoModel.clear(); } -void MainWindow::onTodoParsing(const QString& filename, int lineNo, int ch, const QString& line) +void MainWindow::onTodoFound(const QString& filename, int lineNo, int ch, const QString& line) { mTodoModel.addItem(filename,lineNo,ch,line); } @@ -4470,6 +4476,7 @@ void MainWindow::closeProject(bool refreshEditor) if (!mQuitting) { mBookmarkModel->setIsForProject(false); mDebugger->setIsForProject(false); + mTodoModel.setIsForProject(false); // Clear error browser clearIssues(); updateProjectView(); @@ -7111,6 +7118,11 @@ const PBookmarkModel &MainWindow::bookmarkModel() const return mBookmarkModel; } +TodoModel *MainWindow::todoModel() +{ + return &mTodoModel; +} + void MainWindow::on_actionAdd_bookmark_triggered() { diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 21b3123c..1e0fc487 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -196,6 +196,8 @@ public: const PBookmarkModel &bookmarkModel() const; + TodoModel* todoModel(); + Editor* openFile(const QString& filename, bool activate=true, QTabWidget* page=nullptr); void openProject(const QString& filename, bool openFiles = true); void changeOptions(const QString& widgetName=QString(), const QString& groupName=QString()); @@ -235,8 +237,9 @@ public slots: void onEditorTabContextMenu(QTabWidget* tabWidget, const QPoint& pos); void disableDebugActions(); void enableDebugActions(); - void onTodoParseStarted(const QString& filename); - void onTodoParsing(const QString& filename, int lineNo, int ch, const QString& line); + void onTodoParsingFile(const QString& filename); + void onTodoParseStarted(); + void onTodoFound(const QString& filename, int lineNo, int ch, const QString& line); void onTodoParseFinished(); void setActiveBreakpoint(QString FileName, int Line, bool setFocus); void updateDPI(int oldDPI, int newDPI); diff --git a/RedPandaIDE/project.cpp b/RedPandaIDE/project.cpp index 1aa2226a..54f50712 100644 --- a/RedPandaIDE/project.cpp +++ b/RedPandaIDE/project.cpp @@ -456,6 +456,15 @@ QList Project::unitList() return units; } +QStringList Project::unitFiles() +{ + QStringList units; + foreach(PProjectUnit unit, mUnits) { + units.append(unit->fileName()); + } + return units; +} + void Project::rebuildNodes() { mModel.beginUpdate(); diff --git a/RedPandaIDE/project.h b/RedPandaIDE/project.h index 1100969d..8e71e4f0 100644 --- a/RedPandaIDE/project.h +++ b/RedPandaIDE/project.h @@ -230,6 +230,7 @@ public: Editor* unitEditor(const ProjectUnit* unit) const; QList unitList(); + QStringList unitFiles(); PProjectModelNode pointerToNode(ProjectModelNode * p, PProjectModelNode parent=PProjectModelNode()); void rebuildNodes(); diff --git a/RedPandaIDE/todoparser.cpp b/RedPandaIDE/todoparser.cpp index 980f76e1..ba7eea79 100644 --- a/RedPandaIDE/todoparser.cpp +++ b/RedPandaIDE/todoparser.cpp @@ -18,8 +18,6 @@ #include "mainwindow.h" #include "editor.h" #include "editorlist.h" -#include "HighlighterManager.h" -#include "qsynedit/Constants.h" TodoParser::TodoParser(QObject *parent) : QObject(parent), mMutex(QMutex::Recursive) @@ -27,7 +25,7 @@ TodoParser::TodoParser(QObject *parent) : QObject(parent), mThread = nullptr; } -void TodoParser::parseFile(const QString &filename) +void TodoParser::parseFile(const QString &filename,bool isForProject) { QMutexLocker locker(&mMutex); if (mThread) { @@ -42,10 +40,40 @@ void TodoParser::parseFile(const QString &filename) mThread = nullptr; } }); + if (!isForProject) { + connect(mThread, &TodoThread::parseStarted, + pMainWindow, &MainWindow::onTodoParseStarted); + } + connect(mThread, &TodoThread::parsingFile, + pMainWindow, &MainWindow::onTodoParsingFile); + connect(mThread, &TodoThread::todoFound, + pMainWindow, &MainWindow::onTodoFound); + connect(mThread, &TodoThread::parseFinished, + pMainWindow, &MainWindow::onTodoParseFinished); + mThread->start(); +} + +void TodoParser::parseFiles(const QStringList &files) +{ + QMutexLocker locker(&mMutex); + if (mThread) { + return; + } + mThread = new TodoThread(files); + connect(mThread,&QThread::finished, + [this] { + QMutexLocker locker(&mMutex); + if (mThread) { + mThread->deleteLater(); + mThread = nullptr; + } + }); connect(mThread, &TodoThread::parseStarted, pMainWindow, &MainWindow::onTodoParseStarted); + connect(mThread, &TodoThread::parsingFile, + pMainWindow, &MainWindow::onTodoParsingFile); connect(mThread, &TodoThread::todoFound, - pMainWindow, &MainWindow::onTodoParsing); + pMainWindow, &MainWindow::onTodoFound); connect(mThread, &TodoThread::parseFinished, pMainWindow, &MainWindow::onTodoParseFinished); mThread->start(); @@ -56,21 +84,42 @@ bool TodoParser::parsing() const return (mThread!=nullptr); } -TodoThread::TodoThread(const QString& filename, QObject *parent): QThread(parent) +TodoThread::TodoThread(const QString &filename, QObject *parent): QThread(parent) { mFilename = filename; + mParseFiles = false; } -void TodoThread::run() +TodoThread::TodoThread(const QStringList &files, QObject *parent): QThread(parent) +{ + mFiles = files; + mParseFiles = true; +} + +void TodoThread::parseFile() { QSynedit::PHighlighter highlighter = highlighterManager.getCppHighlighter(); - emit parseStarted(mFilename); - auto action = finally([this]{ - emit parseFinished(); - }); + emit parseStarted(); + doParseFile(mFilename,highlighter); + emit parseFinished(); +} + +void TodoThread::parseFiles() +{ + QSynedit::PHighlighter highlighter = highlighterManager.getCppHighlighter(); + emit parseStarted(); + foreach(const QString& filename,mFiles) { + doParseFile(filename,highlighter); + } + emit parseFinished(); +} + +void TodoThread::doParseFile(const QString &filename, QSynedit::PHighlighter highlighter) +{ + emit parsingFile(filename); QStringList lines; - if (!pMainWindow->editorList()->getContentFromOpenedEditor(mFilename,lines)) { - return; + if (!pMainWindow->editorList()->getContentFromOpenedEditor(filename,lines)) { + lines = readFileToLines(filename); } QSynedit::PHighlighterAttribute commentAttr = highlighter->getAttribute(SYNS_AttrComment); @@ -82,6 +131,7 @@ void TodoThread::run() attr = highlighter->getTokenAttribute(); if (attr == commentAttr) { QString token = highlighter->getToken(); + qDebug()<=0) { emit todoFound( @@ -95,29 +145,54 @@ void TodoThread::run() highlighter->next(); } } + +} + +void TodoThread::run() +{ + if (mParseFiles) { + parseFiles(); + } else { + parseFile(); + } } TodoModel::TodoModel(QObject *parent) : QAbstractListModel(parent) { - + mIsForProject=false; } void TodoModel::addItem(const QString &filename, int lineNo, int ch, const QString &line) { - beginInsertRows(QModelIndex(),mItems.count(),mItems.count()); + QList &items=getItems(mIsForProject); + beginInsertRows(QModelIndex(),items.count(),items.count()); PTodoItem item = std::make_shared(); item->filename = filename; item->lineNo = lineNo; item->ch = ch; item->line = line; - mItems.append(item); + items.append(item); endInsertRows(); } +void TodoModel::removeTodosForFile(const QString &filename) +{ + QList &items=getItems(mIsForProject); + for(int i=items.count()-1;i>=0;i--) { + PTodoItem item = items[i]; + if (item->filename==filename) { + beginRemoveRows(QModelIndex(),i,i); + items.removeAt(i); + endRemoveRows(); + } + } +} + void TodoModel::clear() { beginResetModel(); - mItems.clear(); + QList &items=getItems(mIsForProject); + items.clear(); endResetModel(); } @@ -125,20 +200,46 @@ PTodoItem TodoModel::getItem(const QModelIndex &index) { if (!index.isValid()) return PTodoItem(); - return mItems[index.row()]; + return getItems(mIsForProject)[index.row()]; +} + +QList &TodoModel::getItems(bool forProject) +{ + return forProject?mProjectItems:mItems; +} + +const QList &TodoModel::getConstItems(bool forProject) const +{ + return forProject?mProjectItems:mItems; +} + +bool TodoModel::isForProject() const +{ + return mIsForProject; +} + +void TodoModel::setIsForProject(bool newIsForProject) +{ + if (mIsForProject!=newIsForProject) { + beginResetModel(); + mIsForProject = newIsForProject; + endResetModel(); + } } int TodoModel::rowCount(const QModelIndex &) const { - return mItems.count(); + const QList &items=getConstItems(mIsForProject); + return items.count(); } QVariant TodoModel::data(const QModelIndex &index, int role) const { + const QList &items=getConstItems(mIsForProject); if (!index.isValid()) return QVariant(); if (role==Qt::DisplayRole) { - PTodoItem item = mItems[index.row()]; + PTodoItem item = items[index.row()]; switch(index.column()) { case 0: return item->filename; diff --git a/RedPandaIDE/todoparser.h b/RedPandaIDE/todoparser.h index 825ec870..59576613 100644 --- a/RedPandaIDE/todoparser.h +++ b/RedPandaIDE/todoparser.h @@ -21,6 +21,8 @@ #include #include #include +#include "HighlighterManager.h" +#include "qsynedit/Constants.h" struct TodoItem { QString filename; @@ -37,20 +39,25 @@ public: explicit TodoModel(QObject* parent=nullptr); void addItem(const QString& filename, int lineNo, int ch, const QString& line); + void removeTodosForFile(const QString& filename); void clear(); PTodoItem getItem(const QModelIndex& index); +private: + QList &getItems(bool forProject); + const QList &getConstItems(bool forProject) const; private: QList mItems; + QList mProjectItems; + bool mIsForProject; // QAbstractItemModel interface public: int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - - // QAbstractItemModel interface -public: int columnCount(const QModelIndex &parent) const override; + bool isForProject() const; + void setIsForProject(bool newIsForProject); }; class TodoThread: public QThread @@ -58,12 +65,20 @@ class TodoThread: public QThread Q_OBJECT public: explicit TodoThread(const QString& filename, QObject* parent = nullptr); + explicit TodoThread(const QStringList& files, QObject* parent = nullptr); signals: - void parseStarted(const QString& filename); + void parseStarted(); + void parsingFile(const QString& fileName); void todoFound(const QString& filename, int lineNo, int ch, const QString& line); void parseFinished(); +private: + void parseFile(); + void parseFiles(); + void doParseFile(const QString& filename, QSynedit::PHighlighter highlighter); private: QString mFilename; + QStringList mFiles; + bool mParseFiles; // QThread interface protected: @@ -77,7 +92,8 @@ class TodoParser : public QObject Q_OBJECT public: explicit TodoParser(QObject *parent = nullptr); - void parseFile(const QString& filename); + void parseFile(const QString& filename,bool isForProject); + void parseFiles(const QStringList& files); bool parsing() const; private: