File indexing completed on 2024-05-05 04:39:24

0001 /*
0002     SPDX-FileCopyrightText: 2009 Aleix Pol <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "cmakecommandscontents.h"
0008 #include <interfaces/iruntimecontroller.h>
0009 #include <interfaces/iruntime.h>
0010 #include <interfaces/icore.h>
0011 #include <interfaces/idocumentation.h>
0012 #include <interfaces/idocumentationcontroller.h>
0013 #include "cmakebuilderconfig.h"
0014 #include "cmakedoc.h"
0015 #include <QProcess>
0016 #include <KLocalizedString>
0017 
0018 #include <array>
0019 
0020 static const std::array<QString, 6> args = {
0021     QStringLiteral("--help-command"),
0022     QStringLiteral("--help-variable"),
0023     QStringLiteral("--help-module"),
0024     QStringLiteral("--help-property"),
0025     QStringLiteral("--help-policy"),
0026     QString(),
0027 };
0028 static const std::array<QString, 5> modules = {
0029     i18nc("@item cmake", "Commands"),
0030     i18nc("@item cmake", "Variables"),
0031     i18nc("@item cmake", "Modules"),
0032     i18nc("@item cmake", "Properties"),
0033     i18nc("@item cmake", "Policies"),
0034 };
0035 
0036 CMakeCommandsContents::CMakeCommandsContents(QObject* parent)
0037      : QAbstractItemModel(parent)
0038      , m_namesForType(CMakeDocumentation::EOType)
0039 {
0040     for (int i = 0; i <= CMakeDocumentation::Policy; ++i) {
0041         const QStringList params = { args[i]+QStringLiteral("-list") };
0042 
0043         auto* process = new QProcess(this);
0044         process->setProperty("type", i);
0045         process->setProgram(CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile());
0046         process->setArguments(params);
0047         KDevelop::ICore::self()->runtimeController()->currentRuntime()->startProcess(process);
0048 
0049         connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
0050                 this, &CMakeCommandsContents::processOutput);
0051     }
0052 }
0053 
0054 void CMakeCommandsContents::processOutput(int code)
0055 {
0056     auto* process = qobject_cast<QProcess*>(sender());
0057     if (code!=0) {
0058         qDebug() << "failed" << process;
0059         return;
0060     }
0061 
0062     const CMakeDocumentation::Type type = CMakeDocumentation::Type(process->property("type").toInt());
0063 
0064     QTextStream stream(process);
0065     QString line = stream.readLine(); //discard first line
0066     QVector<QString> names;
0067     while(stream.readLineInto(&line)) {
0068         names += line;
0069     }
0070 
0071     beginInsertRows(index(type, 0, {}), 0, names.count()-1);
0072     for (auto& name : qAsConst(names)) {
0073         m_typeForName.insert(name, type);
0074     }
0075     m_namesForType[type] = names;
0076     endInsertRows();
0077 }
0078 
0079 CMakeDocumentation::Type CMakeCommandsContents::typeFor(const QString& identifier) const
0080 {
0081     //TODO can do much better
0082     if(m_typeForName.contains(identifier)) {
0083         return m_typeForName[identifier];
0084     } else if(m_typeForName.contains(identifier.toLower())) {
0085         return m_typeForName[identifier.toLower()];
0086     } else if(m_typeForName.contains(identifier.toUpper())) {
0087         return m_typeForName[identifier.toUpper()];
0088     }
0089     return CMakeDocumentation::EOType;
0090 }
0091 
0092 QString CMakeCommandsContents::descriptionForIdentifier(const QString& id, CMakeDocumentation::Type t) const
0093 {
0094     QString desc;
0095     if(args[t].size() != 0) {
0096         desc = CMake::executeProcess(CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile(), { args[t], id.simplified() });
0097         desc.remove(QLatin1String(":ref:"));
0098 
0099         const QString rst2html = QStandardPaths::findExecutable(QStringLiteral("rst2html"));
0100         if (rst2html.isEmpty()) {
0101             desc = (QLatin1String("<html><body><pre><code>") + desc.toHtmlEscaped() + QLatin1String("</code></pre>")
0102                 + i18n("<p>For better CMake documentation rendering, install rst2html.</p>")
0103                 + QLatin1String("</body></html>"));
0104         } else {
0105             QProcess p;
0106             p.start(rst2html, { QStringLiteral("--no-toc-backlinks"), QStringLiteral("--quiet") });
0107             p.write(desc.toUtf8());
0108             p.closeWriteChannel();
0109             p.waitForFinished();
0110             desc = QString::fromUtf8(p.readAllStandardOutput());
0111         }
0112     }
0113 
0114     return desc;
0115 }
0116 
0117 
0118 void CMakeCommandsContents::showItemAt(const QModelIndex& idx) const
0119 {
0120     if(idx.isValid() && int(idx.internalId())>=0) {
0121         QString desc=CMakeDoc::s_provider->descriptionForIdentifier(idx.data().toString(),
0122                                                                     (ICMakeDocumentation::Type) idx.parent().row());
0123         CMakeDoc::Ptr doc(new CMakeDoc(idx.data().toString(), desc));
0124 
0125         KDevelop::ICore::self()->documentationController()->showDocumentation(doc);
0126     }
0127 }
0128 
0129 QModelIndex CMakeCommandsContents::parent(const QModelIndex& child) const
0130 {
0131     if(child.isValid() && child.column()==0 && int(child.internalId())>=0)
0132         return createIndex(child.internalId(),0, -1);
0133     return QModelIndex();
0134 }
0135 
0136 QModelIndex CMakeCommandsContents::index(int row, int column, const QModelIndex& parent) const
0137 {
0138     if(row<0 || column!=0)
0139         return QModelIndex();
0140     if(!parent.isValid() && row==ICMakeDocumentation::EOType)
0141         return QModelIndex();
0142 
0143     return createIndex(row,column, int(parent.isValid() ? parent.row() : -1));
0144 }
0145 
0146 int CMakeCommandsContents::rowCount(const QModelIndex& parent) const
0147 {
0148     if(!parent.isValid())
0149         return ICMakeDocumentation::EOType;
0150     else if(int(parent.internalId())<0) {
0151         int ss=names((ICMakeDocumentation::Type) parent.row()).size();
0152         return ss;
0153     }
0154     return 0;
0155 }
0156 
0157 QVariant CMakeCommandsContents::data(const QModelIndex& index, int role) const
0158 {
0159     if (index.isValid()) {
0160         if(role==Qt::DisplayRole) {
0161             int internal(index.internalId());
0162             if(internal>=0)
0163                 return m_namesForType[internal].count() > index.row() ? QVariant(m_namesForType[internal].at(index.row())) : QVariant();
0164             else
0165                 return modules[index.row()];
0166         }
0167     }
0168     return QVariant();
0169 }
0170 
0171 int CMakeCommandsContents::columnCount(const QModelIndex& /*parent*/) const
0172 {
0173     return 1;
0174 }
0175 
0176 QVector<QString> CMakeCommandsContents::names(ICMakeDocumentation::Type t) const
0177 {
0178     return m_namesForType[t];
0179 }
0180 
0181 #include "moc_cmakecommandscontents.cpp"