diff --git a/addons/project/kateprojectcodeanalysistool.h b/addons/project/kateprojectcodeanalysistool.h index 57b3f1a63..8fe54fff3 100644 --- a/addons/project/kateprojectcodeanalysistool.h +++ b/addons/project/kateprojectcodeanalysistool.h @@ -1,94 +1,103 @@ /* This file is part of the Kate project. * * Copyright (C) 2017 Héctor Mesa Jiménez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KATE_PROJECT_CODE_ANALYSIS_TOOL_H #define KATE_PROJECT_CODE_ANALYSIS_TOOL_H #include #include #include "kateproject.h" /** * Information provider for a code analysis tool */ class KateProjectCodeAnalysisTool: public QObject { Q_OBJECT protected: explicit KateProjectCodeAnalysisTool(QObject *parent = nullptr); /** * Current project */ KateProject *m_project; public: virtual ~KateProjectCodeAnalysisTool(); /** * bind to this project * @param project project this tool will analyze */ virtual void setProject(KateProject *project); /** * @return tool descriptive name */ virtual QString name() = 0; + /** + * @returns a string containing the file extensions this + * tool should be run, separated by '|', + * e.g. "cpp|cxx" + * NOTE that this is used directly as part of a regular expression. + * If more flexibility is required this method probably will change + */ + virtual QString fileExtensions() = 0; + /** * filter relevant files * @param files set of files in project * @return relevant files that can be analyzed */ virtual QStringList filter(const QStringList &files) = 0; /** * @return tool path */ virtual QString path() = 0; /** * @return arguments required for the tool */ virtual QStringList arguments() = 0; /** * @return warning message when the tool is not installed */ virtual QString notInstalledMessage() = 0; /** * parse output line * @param line * @return file, line, severity, message */ virtual QStringList parseLine(const QString &line) = 0; /** * @return messages passed to the tool through stdin */ virtual QString stdinMessages() = 0; }; Q_DECLARE_METATYPE(KateProjectCodeAnalysisTool*) #endif // KATE_PROJECT_CODE_ANALYSIS_TOOL_H diff --git a/addons/project/kateprojectinfoviewcodeanalysis.cpp b/addons/project/kateprojectinfoviewcodeanalysis.cpp index e9057c8d5..8bc170f0c 100644 --- a/addons/project/kateprojectinfoviewcodeanalysis.cpp +++ b/addons/project/kateprojectinfoviewcodeanalysis.cpp @@ -1,228 +1,248 @@ /* This file is part of the Kate project. * * Copyright (C) 2012 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kateprojectinfoviewcodeanalysis.h" #include "kateprojectpluginview.h" #include "kateprojectcodeanalysistool.h" #include "tools/kateprojectcodeanalysisselector.h" -#include -#include #include +#include +#include +#include #include #include KateProjectInfoViewCodeAnalysis::KateProjectInfoViewCodeAnalysis(KateProjectPluginView *pluginView, KateProject *project) : QWidget() , m_pluginView(pluginView) , m_project(project) , m_messageWidget(nullptr) , m_startStopAnalysis(new QPushButton(i18n("Start Analysis..."))) , m_treeView(new QTreeView()) , m_model(new QStandardItemModel(m_treeView)) , m_analyzer(nullptr) , m_analysisTool(nullptr) , m_toolSelector(new QComboBox()) { /** * default style */ m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_treeView->setUniformRowHeights(true); m_treeView->setRootIsDecorated(false); m_model->setHorizontalHeaderLabels(QStringList() << i18n("File") << i18n("Line") << i18n("Severity") << i18n("Message")); /** * attach model * kill selection model */ QItemSelectionModel *m = m_treeView->selectionModel(); m_treeView->setModel(m_model); delete m; m_treeView->setSortingEnabled(true); m_treeView->sortByColumn(1, Qt::AscendingOrder); m_treeView->sortByColumn(2, Qt::AscendingOrder); /** - * attach model to code analysis selector + * Connect selection change callback + * and attach model to code analysis selector */ + connect(m_toolSelector, static_cast(&QComboBox::currentIndexChanged), + this, &KateProjectInfoViewCodeAnalysis::slotToolSelectionChanged); m_toolSelector->setModel(KateProjectCodeAnalysisSelector::model(this)); /** * layout widget */ QVBoxLayout *layout = new QVBoxLayout; layout->setSpacing(0); - layout->addWidget(m_treeView); + // top: selector and buttons... QHBoxLayout *hlayout = new QHBoxLayout; layout->addLayout(hlayout); hlayout->setSpacing(0); - hlayout->addStretch(); hlayout->addWidget(m_toolSelector); + auto infoButton = new QPushButton(QIcon::fromTheme(QStringLiteral("documentinfo")), QString(), this); + infoButton->setFocusPolicy(Qt::FocusPolicy::TabFocus); + connect(infoButton, &QPushButton::clicked, this, + [this]() { + QToolTip::showText(QCursor::pos(), m_toolInfoText); + }); + hlayout->addWidget(infoButton); hlayout->addWidget(m_startStopAnalysis); + hlayout->addStretch(); + // below: result list... + layout->addWidget(m_treeView); setLayout(layout); /** * connect needed signals */ connect(m_startStopAnalysis, &QPushButton::clicked, this, &KateProjectInfoViewCodeAnalysis::slotStartStopClicked); connect(m_treeView, &QTreeView::clicked, this, &KateProjectInfoViewCodeAnalysis::slotClicked); } KateProjectInfoViewCodeAnalysis::~KateProjectInfoViewCodeAnalysis() { } +void KateProjectInfoViewCodeAnalysis::slotToolSelectionChanged(int) +{ + m_analysisTool = m_toolSelector->currentData(Qt::UserRole + 1).value(); + m_toolInfoText = i18n("The selected tool will be run on all project files which match this list of file extensions:
%1", + m_analysisTool->fileExtensions()); +} + void KateProjectInfoViewCodeAnalysis::slotStartStopClicked() { /** * get files for the external tool */ m_analysisTool = m_toolSelector->currentData(Qt::UserRole + 1).value(); m_analysisTool->setProject(m_project); /** * clear existing entries */ m_model->removeRows(0, m_model->rowCount(), QModelIndex()); /** * launch cppcheck */ m_analyzer = new QProcess(this); m_analyzer->setProcessChannelMode(QProcess::MergedChannels); connect(m_analyzer, &QProcess::readyRead, this, &KateProjectInfoViewCodeAnalysis::slotReadyRead); connect(m_analyzer, static_cast(&QProcess::finished), this, &KateProjectInfoViewCodeAnalysis::finished); m_analyzer->start(m_analysisTool->path(), m_analysisTool->arguments()); if (m_messageWidget) { delete m_messageWidget; m_messageWidget = nullptr; } if (!m_analyzer->waitForStarted()) { m_messageWidget = new KMessageWidget(); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setMessageType(KMessageWidget::Warning); m_messageWidget->setWordWrap(false); m_messageWidget->setText(m_analysisTool->notInstalledMessage()); - static_cast(layout())->insertWidget(0, m_messageWidget); + static_cast(layout())->addWidget(m_messageWidget); m_messageWidget->animatedShow(); return; } /** * write files list and close write channel */ const QString stdinMessage = m_analysisTool->stdinMessages(); if (!stdinMessage.isEmpty()) { m_analyzer->write(stdinMessage.toLocal8Bit()); } m_analyzer->closeWriteChannel(); } void KateProjectInfoViewCodeAnalysis::slotReadyRead() { /** * get results of analysis */ while (m_analyzer->canReadLine()) { /** * get one line, split it, skip it, if too few elements */ QString line = QString::fromLocal8Bit(m_analyzer->readLine()); QStringList elements = m_analysisTool->parseLine(line); if (elements.size() < 4) { continue; } /** * feed into model */ QList items; QStandardItem *fileNameItem = new QStandardItem(QFileInfo(elements[0]).fileName()); fileNameItem->setToolTip(elements[0]); items << fileNameItem; items << new QStandardItem(elements[1]); items << new QStandardItem(elements[2]); const auto message = elements[3].simplified(); auto messageItem = new QStandardItem(message); messageItem->setToolTip(message); items << messageItem; m_model->appendRow(items); } /** * tree view polish ;) */ m_treeView->resizeColumnToContents(2); m_treeView->resizeColumnToContents(1); m_treeView->resizeColumnToContents(0); } void KateProjectInfoViewCodeAnalysis::slotClicked(const QModelIndex &index) { /** * get path */ QString filePath = m_model->item(index.row(), 0)->toolTip(); if (filePath.isEmpty()) { return; } /** * create view */ KTextEditor::View *view = m_pluginView->mainWindow()->openUrl(QUrl::fromLocalFile(filePath)); if (!view) { return; } /** * set cursor, if possible */ int line = m_model->item(index.row(), 1)->text().toInt(); if (line >= 1) { view->setCursorPosition(KTextEditor::Cursor(line - 1, 0)); } } void KateProjectInfoViewCodeAnalysis::finished(int exitCode, QProcess::ExitStatus) { m_messageWidget = new KMessageWidget(); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setWordWrap(false); if (exitCode == 0) { m_messageWidget->setMessageType(KMessageWidget::Information); m_messageWidget->setText(i18n("Analysis finished.")); } else { // unfortunately, output was eaten by slotReadyRead() // TODO: get stderr output, show it here m_messageWidget->setMessageType(KMessageWidget::Warning); m_messageWidget->setText(i18n("Analysis failed!")); } - static_cast(layout ())->insertWidget(0, m_messageWidget); + static_cast(layout ())->addWidget(m_messageWidget); m_messageWidget->animatedShow (); } diff --git a/addons/project/kateprojectinfoviewcodeanalysis.h b/addons/project/kateprojectinfoviewcodeanalysis.h index 4a6885259..53d06f199 100644 --- a/addons/project/kateprojectinfoviewcodeanalysis.h +++ b/addons/project/kateprojectinfoviewcodeanalysis.h @@ -1,131 +1,147 @@ /* This file is part of the Kate project. * * Copyright (C) 2010 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KATE_PROJECT_INFO_VIEW_CODE_ANALYSIS_H #define KATE_PROJECT_INFO_VIEW_CODE_ANALYSIS_H #include "kateproject.h" -#include +#include +#include #include +#include #include -#include class KateProjectPluginView; class KateProjectCodeAnalysisTool; class KMessageWidget; /** * View for Code Analysis. * cppcheck and perhaps later more... */ class KateProjectInfoViewCodeAnalysis : public QWidget { Q_OBJECT public: /** * construct project info view for given project * @param pluginView our plugin view * @param project project this view is for */ KateProjectInfoViewCodeAnalysis(KateProjectPluginView *pluginView, KateProject *project); /** * deconstruct info view */ ~KateProjectInfoViewCodeAnalysis() override; /** * our project. * @return project */ KateProject *project() const { return m_project; } private Q_SLOTS: + /** + * Called if the tool is changed (currently via Combobox) + */ + void slotToolSelectionChanged(int); + /** * Called if start/stop button is clicked. */ void slotStartStopClicked(); /** * More checker output is available */ void slotReadyRead(); /** * item got clicked, do stuff, like open document * @param index model index of clicked item */ void slotClicked(const QModelIndex &index); /** * Analysis finished * @param exitCode analyzer process exit code * @param exitStatus analyzer process exit status */ void finished(int exitCode, QProcess::ExitStatus exitStatus); private: /** * our plugin view */ KateProjectPluginView *m_pluginView; /** * our project */ KateProject *m_project; /** * information widget showing a warning about missing ctags. */ KMessageWidget *m_messageWidget; /** * start/stop analysis button */ QPushButton *m_startStopAnalysis; /** * tree view for results */ QTreeView *m_treeView; /** * standard item model for results */ QStandardItemModel *m_model; /** * running analyzer process */ QProcess *m_analyzer; + /** + * currently selected tool + */ KateProjectCodeAnalysisTool *m_analysisTool; + /** + * UI element to select the tool + */ QComboBox *m_toolSelector; + /** + * contains a rich text to explain what the current tool does + */ + QString m_toolInfoText; }; #endif diff --git a/addons/project/tools/kateprojectcodeanalysistoolcppcheck.cpp b/addons/project/tools/kateprojectcodeanalysistoolcppcheck.cpp index ea6a6d7a8..3b674b3fd 100644 --- a/addons/project/tools/kateprojectcodeanalysistoolcppcheck.cpp +++ b/addons/project/tools/kateprojectcodeanalysistoolcppcheck.cpp @@ -1,85 +1,92 @@ /* This file is part of the Kate project. * * Copyright (C) 2017 Héctor Mesa Jiménez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kateprojectcodeanalysistoolcppcheck.h" #include #include KateProjectCodeAnalysisToolCppcheck::KateProjectCodeAnalysisToolCppcheck(QObject *parent) : KateProjectCodeAnalysisTool(parent) { } KateProjectCodeAnalysisToolCppcheck::~KateProjectCodeAnalysisToolCppcheck() { } QString KateProjectCodeAnalysisToolCppcheck::name() { return i18n("cppcheck"); } +QString KateProjectCodeAnalysisToolCppcheck::fileExtensions() +{ + return QStringLiteral("cpp|cxx|cc|c++|c|tpp|txx"); +} + QStringList KateProjectCodeAnalysisToolCppcheck::filter(const QStringList &files) { // c++ files - return files.filter(QRegularExpression(QStringLiteral("\\.(cpp|cxx|cc|c\\+\\+|c|tpp|txx)$"))); + return files.filter(QRegularExpression(QStringLiteral("\\.(") + + fileExtensions().replace(QStringLiteral("+"), QStringLiteral("\\+")) + + QStringLiteral(")$"))); } QString KateProjectCodeAnalysisToolCppcheck::path() { return QStringLiteral("cppcheck"); } QStringList KateProjectCodeAnalysisToolCppcheck::arguments() { QStringList _args; _args << QStringLiteral("-q") << QStringLiteral("--inline-suppr") << QStringLiteral("--enable=all") << QStringLiteral("--template={file}////{line}////{severity}////{message}") << QStringLiteral("--file-list=-"); return _args; } QString KateProjectCodeAnalysisToolCppcheck::notInstalledMessage() { return i18n("Please install 'cppcheck'."); } QStringList KateProjectCodeAnalysisToolCppcheck::parseLine(const QString &line) { return line.split(QRegExp(QStringLiteral("////")), QString::SkipEmptyParts); } QString KateProjectCodeAnalysisToolCppcheck::stdinMessages() { // filenames are written to stdin (--file-list=-) if (!m_project) { return QString(); } return filter(m_project->files()).join(QStringLiteral("\n")); } diff --git a/addons/project/tools/kateprojectcodeanalysistoolcppcheck.h b/addons/project/tools/kateprojectcodeanalysistoolcppcheck.h index 35620251f..1e13a5e40 100644 --- a/addons/project/tools/kateprojectcodeanalysistoolcppcheck.h +++ b/addons/project/tools/kateprojectcodeanalysistoolcppcheck.h @@ -1,51 +1,53 @@ /* This file is part of the Kate project. * * Copyright (C) 2017 Héctor Mesa Jiménez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KATE_PROJECT_CODE_ANALYSIS_TOOL_CPPCHECK_H #define KATE_PROJECT_CODE_ANALYSIS_TOOL_CPPCHECK_H #include "../kateprojectcodeanalysistool.h" /** * Information provider for cppcheck */ class KateProjectCodeAnalysisToolCppcheck: public KateProjectCodeAnalysisTool { public: explicit KateProjectCodeAnalysisToolCppcheck(QObject *parent = nullptr); virtual ~KateProjectCodeAnalysisToolCppcheck() override; virtual QString name() override; + virtual QString fileExtensions() override; + virtual QStringList filter(const QStringList &files) override; virtual QString path() override; virtual QStringList arguments() override; virtual QString notInstalledMessage() override; virtual QStringList parseLine(const QString &line) override; virtual QString stdinMessages() override; }; #endif // KATE_PROJECT_CODE_ANALYSIS_TOOL_CPPCHECK_H diff --git a/addons/project/tools/kateprojectcodeanalysistoolflake8.cpp b/addons/project/tools/kateprojectcodeanalysistoolflake8.cpp index ee3f74f63..a240471d7 100644 --- a/addons/project/tools/kateprojectcodeanalysistoolflake8.cpp +++ b/addons/project/tools/kateprojectcodeanalysistoolflake8.cpp @@ -1,89 +1,94 @@ /* This file is part of the Kate project. * * Copyright (C) 2017 Héctor Mesa Jiménez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kateprojectcodeanalysistoolflake8.h" #include #include KateProjectCodeAnalysisToolFlake8::KateProjectCodeAnalysisToolFlake8(QObject *parent) : KateProjectCodeAnalysisTool(parent) { } KateProjectCodeAnalysisToolFlake8::~KateProjectCodeAnalysisToolFlake8() { } QString KateProjectCodeAnalysisToolFlake8::name() { return i18n("flake8"); } +QString KateProjectCodeAnalysisToolFlake8::fileExtensions() +{ + return QStringLiteral("py"); +} + QStringList KateProjectCodeAnalysisToolFlake8::filter(const QStringList &files) { // for now we expect files with extension - return files.filter(QRegularExpression(QStringLiteral("\\.py$"))); + return files.filter(QRegularExpression(QStringLiteral("\\.(") + fileExtensions() + QStringLiteral(")$"))); } QString KateProjectCodeAnalysisToolFlake8::path() { /* * for now, only the executable in the path can be called, * but it would be great to be able to specify a version * installed in a virtual environment */ return QStringLiteral("flake8"); } QStringList KateProjectCodeAnalysisToolFlake8::arguments() { QStringList _args; _args << QStringLiteral("--exit-zero") /* * translating a flake8 code to a severity level is subjective, * so the code is provided as a severity level. */ << QStringLiteral("--format=%(path)s////%(row)d////%(code)s////%(text)s"); if (m_project) { _args.append(filter(m_project->files())); } return _args; } QString KateProjectCodeAnalysisToolFlake8::notInstalledMessage() { return i18n("Please install 'flake8'."); } QStringList KateProjectCodeAnalysisToolFlake8::parseLine(const QString &line) { return line.split(QRegExp(QStringLiteral("////")), QString::SkipEmptyParts); } QString KateProjectCodeAnalysisToolFlake8::stdinMessages() { return QString(); } diff --git a/addons/project/tools/kateprojectcodeanalysistoolflake8.h b/addons/project/tools/kateprojectcodeanalysistoolflake8.h index 7ccec53cb..533b7923a 100644 --- a/addons/project/tools/kateprojectcodeanalysistoolflake8.h +++ b/addons/project/tools/kateprojectcodeanalysistoolflake8.h @@ -1,51 +1,53 @@ /* This file is part of the Kate project. * * Copyright (C) 2017 Héctor Mesa Jiménez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KATE_PROJECT_CODE_ANALYSIS_TOOL_FLAKE8_H #define KATE_PROJECT_CODE_ANALYSIS_TOOL_FLAKE8_H #include "../kateprojectcodeanalysistool.h" /** * Information provider for flake8 */ class KateProjectCodeAnalysisToolFlake8: public KateProjectCodeAnalysisTool { public: explicit KateProjectCodeAnalysisToolFlake8(QObject *parent = nullptr); virtual ~KateProjectCodeAnalysisToolFlake8() override; virtual QString name() override; + virtual QString fileExtensions() override; + virtual QStringList filter(const QStringList &files) override; virtual QString path() override; virtual QStringList arguments() override; virtual QString notInstalledMessage() override; virtual QStringList parseLine(const QString &line) override; virtual QString stdinMessages() override; }; #endif // KATE_PROJECT_CODE_ANALYSIS_TOOL_FLAKE8_H