RedPanda-CPP/RedPandaIDE/todoparser.cpp

302 lines
7.9 KiB
C++
Raw Normal View History

2021-12-26 23:18:28 +08:00
/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2021-10-03 17:18:43 +08:00
#include "todoparser.h"
#include "mainwindow.h"
#include "editor.h"
#include "editorlist.h"
#include <QRegularExpression>
static QRegularExpression todoReg("\\b(todo|fixme)\\b", QRegularExpression::CaseInsensitiveOption);
2022-01-04 16:50:54 +08:00
TodoParser::TodoParser(QObject *parent) : QObject(parent),
mMutex()
2021-10-03 17:18:43 +08:00
{
mThread = nullptr;
}
void TodoParser::parseFile(const QString &filename,bool isForProject)
2021-10-03 17:18:43 +08:00
{
QMutexLocker locker(&mMutex);
if (mThread) {
return;
}
mThread = new TodoThread(filename);
connect(mThread,&QThread::finished,
[this] {
QMutexLocker locker(&mMutex);
if (mThread) {
mThread->deleteLater();
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;
}
});
2021-10-03 17:18:43 +08:00
connect(mThread, &TodoThread::parseStarted,
pMainWindow, &MainWindow::onTodoParseStarted);
connect(mThread, &TodoThread::parsingFile,
pMainWindow, &MainWindow::onTodoParsingFile);
2021-10-03 17:18:43 +08:00
connect(mThread, &TodoThread::todoFound,
pMainWindow, &MainWindow::onTodoFound);
2021-10-03 17:18:43 +08:00
connect(mThread, &TodoThread::parseFinished,
pMainWindow, &MainWindow::onTodoParseFinished);
mThread->start();
}
bool TodoParser::parsing() const
{
return (mThread!=nullptr);
}
TodoThread::TodoThread(const QString &filename, QObject *parent): QThread(parent)
2021-10-03 17:18:43 +08:00
{
mFilename = filename;
mParseFiles = false;
2021-10-03 17:18:43 +08:00
}
TodoThread::TodoThread(const QStringList &files, QObject *parent): QThread(parent)
{
mFiles = files;
mParseFiles = true;
}
void TodoThread::parseFile()
2021-10-03 17:18:43 +08:00
{
QSynedit::PSyntaxer syntaxer = syntaxerManager.getSyntaxer(QSynedit::ProgrammingLanguage::CPP);
emit parseStarted();
2022-12-10 21:23:49 +08:00
doParseFile(mFilename,syntaxer);
emit parseFinished();
}
void TodoThread::parseFiles()
{
QSynedit::PSyntaxer highlighter = syntaxerManager.getSyntaxer(QSynedit::ProgrammingLanguage::CPP);
emit parseStarted();
foreach(const QString& filename,mFiles) {
doParseFile(filename,highlighter);
}
emit parseFinished();
}
2022-12-10 21:23:49 +08:00
void TodoThread::doParseFile(const QString &filename, QSynedit::PSyntaxer syntaxer)
{
emit parsingFile(filename);
2021-10-03 17:18:43 +08:00
QStringList lines;
if (!pMainWindow->editorList()->getContentFromOpenedEditor(filename,lines)) {
lines = readFileToLines(filename);
2021-10-03 17:18:43 +08:00
}
2022-12-10 21:23:49 +08:00
syntaxer->resetState();
2021-10-03 17:18:43 +08:00
for (int i =0;i<lines.count();i++) {
2022-12-10 21:23:49 +08:00
syntaxer->setLine(lines[i],i);
while (!syntaxer->eol()) {
2022-12-10 20:45:13 +08:00
QSynedit::PTokenAttribute attr;
2022-12-10 21:23:49 +08:00
attr = syntaxer->getTokenAttribute();
if (attr && attr->tokenType() == QSynedit::TokenType::Comment) {
2022-12-10 21:23:49 +08:00
QString token = syntaxer->getToken();
int pos = token.indexOf(todoReg);
2021-10-03 17:18:43 +08:00
if (pos>=0) {
emit todoFound(
2022-10-23 00:39:24 +08:00
filename,
2021-10-03 17:18:43 +08:00
i+1,
2022-12-10 21:23:49 +08:00
pos+syntaxer->getTokenPos(),
2021-10-03 17:18:43 +08:00
lines[i].trimmed()
);
2022-10-26 11:10:56 +08:00
break;
2021-10-03 17:18:43 +08:00
}
}
2022-12-10 21:23:49 +08:00
syntaxer->next();
2021-10-03 17:18:43 +08:00
}
}
2021-10-03 17:18:43 +08:00
}
void TodoThread::run()
2021-10-03 17:18:43 +08:00
{
if (mParseFiles) {
parseFiles();
} else {
parseFile();
}
}
2021-10-03 17:18:43 +08:00
TodoModel::TodoModel(QObject *parent) : QAbstractListModel(parent)
{
mIsForProject=false;
2021-10-03 17:18:43 +08:00
}
void TodoModel::addItem(const QString &filename, int lineNo, int ch, const QString &line)
{
QList<PTodoItem> &items=getItems(mIsForProject);
2022-10-26 11:10:56 +08:00
int pos=-1;
for (int i=0;i<items.count();i++) {
int comp=QString::compare(filename,items[i]->filename);
if (comp<0) {
pos=i;
break;
} else if (comp==0) {
if (lineNo<items[i]->lineNo) {
pos=i;
break;
}
}
}
if (pos<0) {
pos=items.count();
}
beginInsertRows(QModelIndex(),pos,pos);
2021-10-03 17:18:43 +08:00
PTodoItem item = std::make_shared<TodoItem>();
item->filename = filename;
item->lineNo = lineNo;
item->ch = ch;
item->line = line;
2022-10-26 11:10:56 +08:00
items.insert(pos,item);
2021-10-03 17:18:43 +08:00
endInsertRows();
}
void TodoModel::removeTodosForFile(const QString &filename)
{
QList<PTodoItem> &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();
}
}
}
2021-10-03 17:18:43 +08:00
void TodoModel::clear()
{
beginResetModel();
QList<PTodoItem> &items=getItems(mIsForProject);
items.clear();
2021-10-03 17:18:43 +08:00
endResetModel();
}
2022-10-23 00:39:24 +08:00
void TodoModel::clear(bool forProject)
{
if (mIsForProject == forProject)
beginResetModel();
QList<PTodoItem> &items=getItems(forProject);
items.clear();
if (mIsForProject == forProject)
endResetModel();
}
2021-10-03 17:18:43 +08:00
PTodoItem TodoModel::getItem(const QModelIndex &index)
{
if (!index.isValid())
return PTodoItem();
return getItems(mIsForProject)[index.row()];
}
QList<PTodoItem> &TodoModel::getItems(bool forProject)
{
return forProject?mProjectItems:mItems;
}
const QList<PTodoItem> &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();
}
2021-10-03 17:18:43 +08:00
}
2021-10-20 18:05:43 +08:00
int TodoModel::rowCount(const QModelIndex &) const
2021-10-03 17:18:43 +08:00
{
const QList<PTodoItem> &items=getConstItems(mIsForProject);
return items.count();
2021-10-03 17:18:43 +08:00
}
QVariant TodoModel::data(const QModelIndex &index, int role) const
{
const QList<PTodoItem> &items=getConstItems(mIsForProject);
2021-10-03 17:18:43 +08:00
if (!index.isValid())
return QVariant();
if (role==Qt::DisplayRole) {
PTodoItem item = items[index.row()];
2021-10-03 17:18:43 +08:00
switch(index.column()) {
case 0:
return item->filename;
case 1:
return item->lineNo;
case 2:
return item->line;
}
}
return QVariant();
}
QVariant TodoModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch(section) {
case 0:
return tr("Filename");
case 1:
return tr("Line");
case 2:
return tr("Content");
}
}
return QVariant();
}
2021-10-20 18:05:43 +08:00
int TodoModel::columnCount(const QModelIndex &) const
2021-10-03 17:18:43 +08:00
{
2022-10-26 11:10:56 +08:00
return 3;
2021-10-03 17:18:43 +08:00
}