From 41de43fa0ad87cfd5bd7c81c63f8b4310ed65015 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 30 Jan 2024 15:15:50 +0100 Subject: [PATCH] Axivion: Use task tree for fetching opened doc issues Change-Id: I34a694a25cebc312b5ce32eccfa1b5ad04680b01 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionoutputpane.cpp | 29 ------ src/plugins/axivion/axivionplugin.cpp | 99 ++++++++++++++++++--- src/plugins/axivion/axivionplugin.h | 2 + src/plugins/axivion/axivionresultparser.cpp | 60 ------------- src/plugins/axivion/axivionresultparser.h | 1 - 5 files changed, 87 insertions(+), 104 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 1efffa79bad..b54b4387c41 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -390,35 +390,6 @@ void IssuesWidget::setTableDto(const Dto::TableInfoDto &dto) m_issuesView->setColumnHidden(counter++, hiddenColumns.contains(header)); } -static QString anyToSimpleString(const Dto::Any &any) -{ - if (any.isString()) - return any.getString(); - if (any.isBool()) - return QString("%1").arg(any.getBool()); - if (any.isDouble()) - return QString::number(any.getDouble()); - if (any.isNull()) - return QString(); // or NULL?? - if (any.isList()) { - const std::vector anyList = any.getList(); - QStringList list; - for (const Dto::Any &inner : anyList) - list << anyToSimpleString(inner); - return list.join(','); - } - if (any.isMap()) { // TODO - const std::map anyMap = any.getMap(); - auto value = anyMap.find("displayName"); - if (value != anyMap.end()) - return anyToSimpleString(value->second); - value = anyMap.find("name"); - if (value != anyMap.end()) - return anyToSimpleString(value->second); - } - return QString(); -} - static Links linksForIssue(const std::map &issueRow) { Links links; diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 9582be3342e..b0dbe993f75 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -68,6 +68,35 @@ QIcon iconForIssue(const QString &prefix) return it.value(); } +QString anyToSimpleString(const Dto::Any &any) +{ + if (any.isString()) + return any.getString(); + if (any.isBool()) + return QString("%1").arg(any.getBool()); + if (any.isDouble()) + return QString::number(any.getDouble()); + if (any.isNull()) + return QString(); // or NULL?? + if (any.isList()) { + const std::vector anyList = any.getList(); + QStringList list; + for (const Dto::Any &inner : anyList) + list << anyToSimpleString(inner); + return list.join(','); + } + if (any.isMap()) { // TODO + const std::map anyMap = any.getMap(); + auto value = anyMap.find("displayName"); + if (value != anyMap.end()) + return anyToSimpleString(value->second); + value = anyMap.find("name"); + if (value != anyMap.end()) + return anyToSimpleString(value->second); + } + return {}; +} + QString IssueListSearch::toQuery() const { if (kind.isEmpty()) @@ -77,11 +106,15 @@ QString IssueListSearch::toQuery() const // TODO other params if (!versionStart.isEmpty()) { result.append(QString("&start=%1").arg( - QString::fromUtf8(QUrl::toPercentEncoding(versionStart)))); + QString::fromUtf8(QUrl::toPercentEncoding(versionStart)))); } if (!versionEnd.isEmpty()) { result.append(QString("&end=%1").arg( - QString::fromUtf8(QUrl::toPercentEncoding(versionEnd)))); + QString::fromUtf8(QUrl::toPercentEncoding(versionEnd)))); + } + if (!filter_path.isEmpty()) { + result.append(QString("&filter_path=%1").arg( + QString::fromUtf8(QUrl::toPercentEncoding(filter_path)))); } if (computeTotalRowCount) result.append("&computeTotalRowCount=true"); @@ -108,6 +141,7 @@ public: std::optional m_currentProjectInfo; bool m_runningQuery = false; TaskTreeRunner m_taskTreeRunner; + std::unordered_map> m_docMarksTrees; }; static AxivionPluginPrivate *dd = nullptr; @@ -438,15 +472,16 @@ Group tableInfoRecipe(const QString &prefix, const TableInfoHandler &handler) void AxivionPluginPrivate::fetchRuleInfo(const QString &id) { + if (!m_currentProjectInfo) + return; + if (m_runningQuery) { QTimer::singleShot(3000, this, [this, id] { fetchRuleInfo(id); }); return; } - const QStringList args = id.split(':'); - QTC_ASSERT(args.size() == 2, return); m_runningQuery = true; - AxivionQuery query(AxivionQuery::RuleInfo, args); + AxivionQuery query(AxivionQuery::RuleInfo, {m_currentProjectInfo->name, "SV" + id}); AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ m_runningQuery = false; @@ -487,16 +522,48 @@ void AxivionPluginPrivate::onDocumentOpened(IDocument *doc) if (!doc || !project->isKnownFile(doc->filePath())) return; - const FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory()); - // for now only style violations - const AxivionQuery query(AxivionQuery::IssuesForFileList, {m_currentProjectInfo->name, "SV", - relative.path()}); - AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); - connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ - handleIssuesForFile(ResultParser::parseIssuesList(result)); + IssueListSearch search; + search.kind = "SV"; + search.filter_path = doc->filePath().relativeChildPath(project->projectDirectory()).path(); + + const auto issuesHandler = [this](const Dto::IssueTableDto &dto) { + IssuesList issues; + const std::vector> &rows = dto.rows; + for (const auto &row : rows) { + ShortIssue issue; + for (auto it = row.cbegin(); it != row.cend(); ++it) { + if (it->first == "id") + issue.id = anyToSimpleString(it->second); + else if (it->first == "state") + issue.state = anyToSimpleString(it->second); + else if (it->first == "errorNumber") + issue.errorNumber = anyToSimpleString(it->second); + else if (it->first == "message") + issue.message = anyToSimpleString(it->second); + else if (it->first == "entity") + issue.entity = anyToSimpleString(it->second); + else if (it->first == "path") + issue.filePath = anyToSimpleString(it->second); + else if (it->first == "severity") + issue.severity = anyToSimpleString(it->second); + else if (it->first == "line") + issue.lineNumber = anyToSimpleString(it->second).toInt(); + } + issues.issues << issue; + } + handleIssuesForFile(issues); + }; + + TaskTree *taskTree = new TaskTree; + taskTree->setRecipe(issueTableRecipe(search, issuesHandler)); + m_docMarksTrees.insert_or_assign(doc, std::unique_ptr(taskTree)); + connect(taskTree, &TaskTree::done, this, [this, doc] { + const auto it = m_docMarksTrees.find(doc); + QTC_ASSERT(it != m_docMarksTrees.end(), return); + it->second.release()->deleteLater(); + m_docMarksTrees.erase(it); }); - connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); }); - runner->start(); + taskTree->start(); } void AxivionPluginPrivate::onDocumentClosed(IDocument *doc) @@ -505,6 +572,10 @@ void AxivionPluginPrivate::onDocumentClosed(IDocument *doc) if (!document) return; + const auto it = m_docMarksTrees.find(doc); + if (it != m_docMarksTrees.end()) + m_docMarksTrees.erase(it); + const TextEditor::TextMarks marks = document->marks(); for (auto m : marks) { if (m->category().id == AxivionTextMarkId) diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 064ba5318dc..7aafa0a22a4 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -31,6 +31,7 @@ struct IssueListSearch QString versionEnd; QString owner; QString pathglob; + QString filter_path; int offset = 0; int limit = 30; bool computeTotalRowCount = false; @@ -64,6 +65,7 @@ std::optional projectInfo(); bool handleCertificateIssue(); QIcon iconForIssue(const QString &prefix); +QString anyToSimpleString(const Dto::Any &any); } // Axivion::Internal diff --git a/src/plugins/axivion/axivionresultparser.cpp b/src/plugins/axivion/axivionresultparser.cpp index b2823e62f7c..f6dbf0310ff 100644 --- a/src/plugins/axivion/axivionresultparser.cpp +++ b/src/plugins/axivion/axivionresultparser.cpp @@ -54,66 +54,6 @@ static BaseResult prehandleHeader(const QByteArray &header, const QByteArray &bo namespace ResultParser { -static QRegularExpression issueCsvLineRegex(const QByteArray &firstCsvLine) -{ - QString pattern = "^"; - for (const QByteArray &part : firstCsvLine.split(',')) { - const QString cleaned = QString::fromUtf8(part).remove(' ').chopped(1).mid(1); - pattern.append(QString("\"(?<" + cleaned + ">.*)\",")); - } - pattern.chop(1); // remove last comma - pattern.append('$'); - const QRegularExpression regex(pattern); - QTC_ASSERT(regex.isValid(), return {}); - return regex; -} - -static void parseCsvIssue(const QByteArray &csv, QList *issues) -{ - QTC_ASSERT(issues, return); - - bool first = true; - std::optional regex; - for (auto &line : csv.split('\n')) { - if (first) { - regex.emplace(issueCsvLineRegex(line)); - first = false; - if (regex.value().pattern().isEmpty()) - return; - continue; - } - if (line.isEmpty()) - continue; - const QRegularExpressionMatch match = regex->match(QString::fromUtf8(line)); - QTC_ASSERT(match.hasMatch(), continue); - // FIXME: some of these are not present for all issue kinds! Limited to SV for now - ShortIssue issue; - issue.id = match.captured("Id"); - issue.state = match.captured("State"); - issue.errorNumber = match.captured("ErrorNumber"); - issue.message = match.captured("Message"); - issue.entity = match.captured("Entity"); - issue.filePath = match.captured("Path"); - issue.severity = match.captured("Severity"); - issue.lineNumber = match.captured("Line").toInt(); - issues->append(issue); - } -} - -IssuesList parseIssuesList(const QByteArray &input) -{ - IssuesList result; - - auto [header, body] = splitHeaderAndBody(input); - BaseResult headerResult = prehandleHeader(header, body); - if (!headerResult.error.isEmpty()) { - result.error = headerResult.error; - return result; - } - parseCsvIssue(body, &result.issues); - return result; -} - QString parseRuleInfo(const QByteArray &input) // html result! { auto [header, body] = splitHeaderAndBody(input); diff --git a/src/plugins/axivion/axivionresultparser.h b/src/plugins/axivion/axivionresultparser.h index 9302af8082b..c0c4967c7ad 100644 --- a/src/plugins/axivion/axivionresultparser.h +++ b/src/plugins/axivion/axivionresultparser.h @@ -43,7 +43,6 @@ public: namespace ResultParser { -IssuesList parseIssuesList(const QByteArray &input); QString parseRuleInfo(const QByteArray &input); } // ResultParser