diff --git a/projectmanagers/cmake/CMakeLists.txt b/projectmanagers/cmake/CMakeLists.txt index 5b23552a64..c4500c0ed7 100644 --- a/projectmanagers/cmake/CMakeLists.txt +++ b/projectmanagers/cmake/CMakeLists.txt @@ -1,112 +1,115 @@ project(cmakemanager) add_definitions(-DTRANSLATION_DOMAIN=\"kdevcmake\") include_directories(${CMAKE_CURRENT_SOURCE_DIR}/parser) add_subdirectory(tests) add_subdirectory(icons) # enable this if you want to have the cmake debug visitor run on each CMakeLists.txt # the debug visitor prints out the Ast for the CMakeLists.txt file. #add_definitions( -DCMAKEDEBUGVISITOR ) ecm_qt_declare_logging_category(cmake_LOG_SRCS HEADER debug.h IDENTIFIER CMAKE CATEGORY_NAME "kdevelop.projectmanagers.cmake" ) set( cmakecommon_SRCS parser/cmListFileLexer.c parser/cmakecachereader.cpp parser/cmakelistsparser.cpp parser/cmakeduchaintypes.cpp cmakeutils.cpp cmakeextraargumentshistory.cpp cmakebuilddirchooser.cpp cmakeserver.cpp ${cmake_LOG_SRCS} ) set( cmakecommon_UI cmakebuilddirchooser.ui ) set( cmakemanager_SRCS testing/ctestutils.cpp testing/ctestfindjob.cpp testing/ctestrunjob.cpp testing/ctestsuite.cpp testing/qttestdelegate.cpp cmakeimportjsonjob.cpp cmakeserverimportjob.cpp cmakenavigationwidget.cpp cmakemanager.cpp cmakeprojectdata.cpp cmakemodelitems.cpp duchain/cmakeparsejob.cpp duchain/usebuilder.cpp duchain/declarationbuilder.cpp duchain/contextbuilder.cpp cmakecodecompletionmodel.cpp # cmakecommitchangesjob.cpp # cmakeedit.cpp ${cmake_LOG_SRCS} ) set( cmakemanager_UI cmakepossibleroots.ui ) set( cmakesettings_SRCS settings/cmakepreferences.cpp settings/cmakecachemodel.cpp settings/cmakecachedelegate.cpp settings/cmakecachemodel.cpp ) ki18n_wrap_ui(cmakesettings_SRCS settings/cmakebuildsettings.ui) set( cmakedoc_SRCS cmakedocumentation.cpp cmakehelpdocumentation.cpp + cmakecommandscontents.cpp ) remove_definitions( -DQT_NO_STL ) if(MSVC) add_definitions(-DYY_NO_UNISTD_H) endif() # Note: This library doesn't follow API/ABI/BC rules and shouldn't have a SOVERSION # Its only purpose is to support the plugin without needing to add all source files # to the plugin target kconfig_add_kcfg_files( cmakecommon_SRCS cmakebuilderconfig.kcfgc ) ki18n_wrap_ui( cmakecommon_SRCS ${cmakecommon_UI} ) add_library( kdevcmakecommon SHARED ${cmakecommon_SRCS} ) target_link_libraries( kdevcmakecommon KF5::TextEditor KDev::Interfaces KDev::Project KDev::Util KDev::Language ) generate_export_header(kdevcmakecommon EXPORT_FILE_NAME cmakecommonexport.h) ki18n_wrap_ui( cmakemanager_SRCS ${cmakemanager_UI} ) add_library( kdevcmakemanagernosettings STATIC ${cmakemanager_SRCS}) target_link_libraries( kdevcmakemanagernosettings KF5::KIOWidgets KDev::Util KDev::Interfaces kdevcmakecommon kdevmakefileresolver KDev::Project KDev::Language KDev::OutputView KF5::TextEditor Qt5::Concurrent) kdevplatform_add_plugin(kdevcmakemanager JSON kdevcmakemanager.json SOURCES ${cmakemanager_SRCS} ${cmakesettings_SRCS}) target_link_libraries( kdevcmakemanager KF5::KIOWidgets KDev::Util KDev::Interfaces kdevcmakecommon kdevmakefileresolver KDev::Project KDev::Language KDev::OutputView KF5::TextEditor Qt5::Concurrent) kdevplatform_add_plugin(kdevcmakedocumentation JSON kdevcmakedocumentation.json SOURCES ${cmakedoc_SRCS}) target_link_libraries( kdevcmakedocumentation KDev::Interfaces kdevcmakecommon KDev::Project KDev::Language KDev::Documentation + KDev::Tests + KF5::ItemModels KF5::TextEditor) install(TARGETS kdevcmakecommon ${INSTALL_TARGETS_DEFAULT_ARGS} ) diff --git a/projectmanagers/cmake/cmakecodecompletionmodel.cpp b/projectmanagers/cmake/cmakecodecompletionmodel.cpp index 661a3ce3ff..830c8c5786 100644 --- a/projectmanagers/cmake/cmakecodecompletionmodel.cpp +++ b/projectmanagers/cmake/cmakecodecompletionmodel.cpp @@ -1,314 +1,314 @@ /* KDevelop CMake Support * * Copyright 2008 Aleix Pol * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakecodecompletionmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cmakeutils.h" #include "icmakedocumentation.h" using namespace KTextEditor; using namespace KDevelop; -QStringList CMakeCodeCompletionModel::s_commands; +QVector CMakeCodeCompletionModel::s_commands; CMakeCodeCompletionModel::CMakeCodeCompletionModel(QObject* parent) : CodeCompletionModel(parent) , m_inside(false) {} bool isFunction(const Declaration* decl) { return decl->abstractType().cast(); } bool isPathChar(const QChar& c) { return c.isLetterOrNumber() || c=='/' || c=='.'; } QString escapePath(QString path) { static const QChar toBeEscaped[] = {'(', ')'}; for(const QChar &ch : toBeEscaped) { path.replace(ch, "\\" + ch); } return path; } void CMakeCodeCompletionModel::completionInvoked(View* view, const Range& range, InvocationType invocationType) { beginResetModel(); if(s_commands.isEmpty()) { ICMakeDocumentation* cmakedoc=CMake::cmakeDocumentation(); if(cmakedoc) s_commands=cmakedoc->names(ICMakeDocumentation::Command); } Q_UNUSED(invocationType); m_declarations.clear(); DUChainReadLocker lock(DUChain::lock()); KTextEditor::Document* d=view->document(); TopDUContext* ctx = DUChain::self()->chainForDocument( d->url() ); QString line=d->line(range.end().line()); // m_inside=line.lastIndexOf('(', range.end().column())>=0; m_inside=line.lastIndexOf('(', range.end().column()-line.size()-1)>=0; for(int l=range.end().line(); l>=0 && !m_inside; --l) { QString cline=d->line(l); QString line=cline.left(cline.indexOf('#')); int close=line.lastIndexOf(')'), open=line.indexOf('('); if(close>=0 && open>=0) { m_inside=open>close; break; } else if(open>=0) { m_inside=true; break; } else if(close>=0) { m_inside=false; break; } } int numRows = 0; if(m_inside) { Cursor start=range.start(); for(; isPathChar(d->characterAt(start)); start-=Cursor(0,1)) {} start+=Cursor(0,1); QString tocomplete=d->text(Range(start, range.end()-Cursor(0,1))); int lastdir=tocomplete.lastIndexOf('/'); QString path = KIO::upUrl(QUrl(d->url())).adjusted(QUrl::StripTrailingSlash).toLocalFile()+'/'; QString basePath; if(lastdir>=0) { basePath=tocomplete.mid(0, lastdir); path+=basePath; } QDir dir(path); QFileInfoList paths=dir.entryInfoList(QStringList() << tocomplete.mid(lastdir+1)+'*', QDir::AllEntries | QDir::NoDotAndDotDot); m_paths.clear(); foreach(const QFileInfo& f, paths) { QString currentPath = f.fileName(); if(f.isDir()) currentPath+='/'; m_paths += currentPath; } numRows += m_paths.count(); } else numRows += s_commands.count(); if(ctx) { typedef QPair DeclPair; QList list=ctx->allDeclarations( ctx->transformToLocalRevision(KTextEditor::Cursor(range.start())), ctx ); foreach(const DeclPair& pair, list) { bool func=isFunction(pair.first); if((func && !m_inside) || (!func && m_inside)) m_declarations.append(pair.first); } numRows+=m_declarations.count(); } setRowCount(numRows); endResetModel(); } CMakeCodeCompletionModel::Type CMakeCodeCompletionModel::indexType(int row) const { if(m_inside) { if(row < m_declarations.count()) { KDevelop::DUChainReadLocker lock; Declaration* dec = m_declarations.at(row).declaration(); if (dec && dec->type()) return Target; else return Variable; } else return Path; } else { if(rowidentifier().toString() : i18n("INVALID"); } } } else if(role==Qt::DisplayRole && index.column()==CodeCompletionModel::Prefix) { switch(type) { case Command: return i18n("Command"); case Variable: return i18n("Variable"); case Macro: return i18n("Macro"); case Path: return i18n("Path"); case Target: return i18n("Target"); } } else if(role==Qt::DecorationRole && index.column()==CodeCompletionModel::Icon) { switch(type) { case Command: return QIcon::fromTheme(QStringLiteral("code-block")); case Variable: return QIcon::fromTheme(QStringLiteral("code-variable")); case Macro: return QIcon::fromTheme(QStringLiteral("code-function")); case Target: return QIcon::fromTheme(QStringLiteral("system-run")); case Path: { QUrl url = QUrl::fromUserInput(m_paths[index.row()-m_declarations.size()]); QString iconName; if (url.isLocalFile()) { // don't read contents even if it is a local file iconName = QMimeDatabase().mimeTypeForFile(url.toLocalFile(), QMimeDatabase::MatchExtension).iconName(); } else { // remote always only looks at the extension iconName = QMimeDatabase().mimeTypeForUrl(url).iconName(); } return QIcon::fromTheme(iconName); } } } else if(role==Qt::DisplayRole && index.column()==CodeCompletionModel::Arguments) { switch(type) { case Variable: case Command: case Path: case Target: break; case Macro: { DUChainReadLocker lock(DUChain::lock()); int pos=index.row(); FunctionType::Ptr func; if(m_declarations[pos].data()) func = m_declarations[pos].data()->abstractType().cast(); if(!func) return QVariant(); QStringList args; foreach(const AbstractType::Ptr& t, func->arguments()) { DelayedType::Ptr delay = t.cast(); args.append(delay ? delay->identifier().toString() : i18n("wrong")); } return QString('('+args.join(QStringLiteral(", "))+')'); } } } return QVariant(); } void CMakeCodeCompletionModel::executeCompletionItem(View* view, const Range& word, const QModelIndex& idx) const { Document* document = view->document(); const int row = idx.row(); switch(indexType(row)) { case Path: { Range r=word; for(QChar c=document->characterAt(r.end()); c.isLetterOrNumber() || c=='.'; c=document->characterAt(r.end())) { r.setEnd(KTextEditor::Cursor(r.end().line(), r.end().column()+1)); } QString path = data(index(row, Name, QModelIndex())).toString(); document->replaceText(r, escapePath(path)); } break; case Macro: case Command: { QString code=data(index(row, Name, QModelIndex())).toString(); if(!document->line(word.start().line()).contains('(')) code.append('('); document->replaceText(word, code); } break; case Variable: { Range r=word, prefix(word.start()-Cursor(0,2), word.start()); QString bef=document->text(prefix); if(r.start().column()>=2 && bef==QLatin1String("${")) r.setStart(KTextEditor::Cursor(r.start().line(), r.start().column()-2)); QString code="${"+data(index(row, Name, QModelIndex())).toString(); if(document->characterAt(word.end())!='}') code+='}'; document->replaceText(r, code); } break; case Target: document->replaceText(word, data(index(row, Name, QModelIndex())).toString()); break; } } diff --git a/projectmanagers/cmake/cmakecodecompletionmodel.h b/projectmanagers/cmake/cmakecodecompletionmodel.h index 762f1f6cab..8260f5889a 100644 --- a/projectmanagers/cmake/cmakecodecompletionmodel.h +++ b/projectmanagers/cmake/cmakecodecompletionmodel.h @@ -1,49 +1,49 @@ /* KDevelop CMake Support * * Copyright 2008 Aleix Pol * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKECODECOMPLETION_H #define CMAKECODECOMPLETION_H #include #include #include #include class CMakeDocumentation; namespace KTextEditor { class Document; class Range; } class CMakeCodeCompletionModel : public KTextEditor::CodeCompletionModel { public: explicit CMakeCodeCompletionModel(QObject *parent); void completionInvoked(KTextEditor::View* view, const KTextEditor::Range& range, InvocationType invocationType) override; QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const override; void executeCompletionItem(KTextEditor::View* view, const KTextEditor::Range& word, const QModelIndex& index) const override; private: enum Type { Command, Variable, Macro, Path, Target }; Type indexType(int row) const; - static QStringList s_commands; + static QVector s_commands; QList< KDevelop::IndexedDeclaration > m_declarations; bool m_inside; QStringList m_paths; }; #endif diff --git a/projectmanagers/cmake/cmakecommandscontents.cpp b/projectmanagers/cmake/cmakecommandscontents.cpp new file mode 100644 index 0000000000..57a97f5011 --- /dev/null +++ b/projectmanagers/cmake/cmakecommandscontents.cpp @@ -0,0 +1,184 @@ +/* KDevelop CMake Support + * + * Copyright 2009 Aleix Pol + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cmakecommandscontents.h" +#include +#include +#include +#include +#include +#include +#include "cmakebuilderconfig.h" +#include "cmakedoc.h" +#include +#include + +static const QVector args = { + QLatin1String("--help-command"), QLatin1String("--help-variable"), QLatin1String("--help-module"), QLatin1String("--help-property"), QLatin1String(), QLatin1String() +}; +static QString modules [] = { + i18n("Commands"), i18n("Variables"), i18n("Modules"), i18n("Properties"), i18n("Policies") +}; + +CMakeCommandsContents::CMakeCommandsContents(QObject* parent) + : QAbstractItemModel(parent) + , m_namesForType(CMakeDocumentation::EOType) +{ + new ModelTest(this, this); + QVector processes; + for(int i=0; i<=CMakeDocumentation::Property; i++) { + const QStringList params = { args[i]+QStringLiteral("-list") }; + + QProcess* process = new QProcess(this); + process->setProperty("type", i); + process->setProgram(CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile()); + process->setArguments(params); + KDevelop::ICore::self()->runtimeController()->currentRuntime()->startProcess(process); + + connect(process, static_cast(&QProcess::finished), this, &CMakeCommandsContents::processOutput); + } +} + +void CMakeCommandsContents::processOutput(int code) +{ + QProcess* process = qobject_cast(sender()); + if (code!=0) { + qDebug() << "failed" << process; + return; + } + + const CMakeDocumentation::Type type = CMakeDocumentation::Type(process->property("type").toInt()); + + QTextStream stream(process); + QString line = stream.readLine(); //discard first line + QMap newEntries; + QVector names; + while(stream.readLineInto(&line)) { + newEntries[line]=type; + names += line; + } + + beginInsertRows(index(type, 0, {}), 0, names.count()-1); + m_typeForName.unite(newEntries); + m_namesForType[type] = names; + endInsertRows(); +} + +CMakeDocumentation::Type CMakeCommandsContents::typeFor(const QString& identifier) const +{ + //TODO can do much better + if(m_typeForName.contains(identifier)) { + return m_typeForName[identifier]; + } else if(m_typeForName.contains(identifier.toLower())) { + return m_typeForName[identifier.toLower()]; + } else if(m_typeForName.contains(identifier.toUpper())) { + return m_typeForName[identifier.toUpper()]; + } + return CMakeDocumentation::EOType; +} + +QString CMakeCommandsContents::descriptionForIdentifier(const QString& id, CMakeDocumentation::Type t) const +{ + QString desc; + if(args[t].size() != 0) { + desc = CMake::executeProcess(CMakeBuilderSettings::self()->cmakeExecutable().toLocalFile(), { args[t], id.simplified() }); + desc = desc.remove(QStringLiteral(":ref:")); + + const QString rst2html = QStandardPaths::findExecutable(QStringLiteral("rst2html")); + if (rst2html.isEmpty()) { + desc = ("
" + desc.toHtmlEscaped() + "
" + + i18n("

For better cmake documentation rendering, install rst2html

") + + ""); + } else { + QProcess p; + p.start(rst2html, { "--no-toc-backlinks" }); + p.write(desc.toUtf8()); + p.closeWriteChannel(); + p.waitForFinished(); + desc = QString::fromUtf8(p.readAllStandardOutput()); + } + } + + return desc; +} + + +void CMakeCommandsContents::showItemAt(const QModelIndex& idx) const +{ + if(idx.isValid() && int(idx.internalId())>=0) { + QString desc=CMakeDoc::s_provider->descriptionForIdentifier(idx.data().toString(), + (ICMakeDocumentation::Type) idx.parent().row()); + CMakeDoc::Ptr doc(new CMakeDoc(idx.data().toString(), desc)); + + KDevelop::ICore::self()->documentationController()->showDocumentation(doc); + } +} + +QModelIndex CMakeCommandsContents::parent(const QModelIndex& child) const +{ + if(child.isValid() && child.column()==0 && int(child.internalId())>=0) + return createIndex(child.internalId(),0, -1); + return QModelIndex(); +} + +QModelIndex CMakeCommandsContents::index(int row, int column, const QModelIndex& parent) const +{ + if(row<0 || column!=0) + return QModelIndex(); + if(!parent.isValid() && row==ICMakeDocumentation::EOType) + return QModelIndex(); + + return createIndex(row,column, int(parent.isValid() ? parent.row() : -1)); +} + +int CMakeCommandsContents::rowCount(const QModelIndex& parent) const +{ + if(!parent.isValid()) + return ICMakeDocumentation::EOType; + else if(int(parent.internalId())<0) { + int ss=names((ICMakeDocumentation::Type) parent.row()).size(); + return ss; + } + return 0; +} + +QVariant CMakeCommandsContents::data(const QModelIndex& index, int role) const +{ + if (index.isValid()) { + if(role==Qt::DisplayRole) { + int internal(index.internalId()); + if(internal>=0) + return m_namesForType[internal].count() > index.row() ? QVariant(m_namesForType[internal].at(index.row())) : QVariant(); + else + return modules[index.row()]; + } + } + return QVariant(); +} + +int CMakeCommandsContents::columnCount(const QModelIndex& /*parent*/) const +{ + return 1; +} + +QVector CMakeCommandsContents::names(ICMakeDocumentation::Type t) const +{ + return m_namesForType[t]; +} diff --git a/projectmanagers/cmake/cmakecommandscontents.h b/projectmanagers/cmake/cmakecommandscontents.h new file mode 100644 index 0000000000..915ca247b6 --- /dev/null +++ b/projectmanagers/cmake/cmakecommandscontents.h @@ -0,0 +1,55 @@ +/* KDevelop CMake Support + * + * Copyright 2009 Aleix Pol + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef CMAKECOMMANDSCONTENTS_H +#define CMAKECOMMANDSCONTENTS_H + +#include +#include +#include + +#include "cmakedocumentation.h" + +class CMakeCommandsContents : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit CMakeCommandsContents(QObject* parent); + + void processOutput(int code); + + int rowCount(const QModelIndex & parent) const override; + + QVariant data(const QModelIndex & index, int role) const override; + + QString descriptionForIdentifier(const QString& id, CMakeDocumentation::Type t) const; + QVector names(CMakeDocumentation::Type t) const; + CMakeDocumentation::Type typeFor(const QString &id) const; + void showItemAt(const QModelIndex &idx) const; + + QModelIndex parent(const QModelIndex & child) const override; + QModelIndex index(int row, int column, const QModelIndex & parent) const override; + int columnCount(const QModelIndex & parent) const override; + +private: + QMap m_typeForName; + QVector> m_namesForType; +}; +#endif // CMAKECOMMANDSCONTENTS_H diff --git a/projectmanagers/cmake/cmakedocumentation.cpp b/projectmanagers/cmake/cmakedocumentation.cpp index 263c06cf84..9a04058c10 100644 --- a/projectmanagers/cmake/cmakedocumentation.cpp +++ b/projectmanagers/cmake/cmakedocumentation.cpp @@ -1,205 +1,147 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakedocumentation.h" #include "cmakeutils.h" #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include + #include "cmakemanager.h" #include "cmakehelpdocumentation.h" #include "cmakebuilderconfig.h" #include "cmakedoc.h" +#include "cmakecommandscontents.h" #include "debug.h" K_PLUGIN_FACTORY_WITH_JSON(CMakeSupportDocFactory, "kdevcmakedocumentation.json", registerPlugin(); ) CMakeDocumentation* CMakeDoc::s_provider=nullptr; KDevelop::IDocumentationProvider* CMakeDoc::provider() const { return s_provider; } CMakeDocumentation::CMakeDocumentation(QObject* parent, const QVariantList&) : KDevelop::IPlugin( QStringLiteral("kdevcmakedocumentation"), parent ) - , m_cmakeExecutable(CMakeBuilderSettings::self()->cmakeExecutable()) - , m_index(nullptr) + , m_index(new CMakeCommandsContents(this)) + , m_flatIndex(new KDescendantsProxyModel(m_index)) { - if (m_cmakeExecutable.isEmpty()) { + m_flatIndex->setSourceModel(m_index); + if (CMakeBuilderSettings::self()->cmakeExecutable().isEmpty()) { setErrorDescription(i18n("Unable to find a CMake executable. Is one installed on the system?")); return; } CMakeDoc::s_provider=this; - m_index= new QStringListModel(this); - initializeModel(); -} - -static const char* const args[] = { "--help-command", "--help-variable", "--help-module", "--help-property", nullptr, nullptr }; - -void CMakeDocumentation::delayedInitialization() -{ - for(int i=0; i<=Property; i++) { - collectIds(QString(args[i])+"-list", (Type) i); - } - - m_index->setStringList(m_typeForName.keys()); -} - -void CMakeDocumentation::collectIds(const QString& param, Type type) -{ - QStringList ids = CMake::executeProcess(m_cmakeExecutable, QStringList(param)).split(QLatin1Char('\n')); - ids.takeFirst(); - foreach(const QString& name, ids) - { - m_typeForName[name]=type; - } } -QStringList CMakeDocumentation::names(CMakeDocumentation::Type t) const +QVector CMakeDocumentation::names(CMakeDocumentation::Type t) const { - return m_typeForName.keys(t); + return m_index->names(t); } QString CMakeDocumentation::descriptionForIdentifier(const QString& id, Type t) const { - QString desc; - if(args[t]) { - desc = CMake::executeProcess(m_cmakeExecutable, { args[t], id.simplified() }); - desc = desc.remove(QStringLiteral(":ref:")); - - const QString rst2html = QStandardPaths::findExecutable(QStringLiteral("rst2html")); - if (rst2html.isEmpty()) { - desc = ("
" + desc.toHtmlEscaped() + "
" - + i18n("

For better cmake documentation rendering, install rst2html

") - + ""); - } else { - QProcess p; - p.start(rst2html, { "--no-toc-backlinks" }); - p.write(desc.toUtf8()); - p.closeWriteChannel(); - p.waitForFinished(); - desc = QString::fromUtf8(p.readAllStandardOutput()); - } - } - - return desc; + return m_index->descriptionForIdentifier(id, t); } KDevelop::IDocumentation::Ptr CMakeDocumentation::description(const QString& identifier, const QUrl &file) const { - initializeModel(); //make it not queued if (!file.isEmpty() && !QMimeDatabase().mimeTypeForUrl(file).inherits(QStringLiteral("text/x-cmake"))) { return KDevelop::IDocumentation::Ptr(); } - QString desc; - if(m_typeForName.contains(identifier)) { - desc=descriptionForIdentifier(identifier, m_typeForName[identifier]); - } else if(m_typeForName.contains(identifier.toLower())) { - desc=descriptionForIdentifier(identifier, m_typeForName[identifier.toLower()]); - } else if(m_typeForName.contains(identifier.toUpper())) { - desc=descriptionForIdentifier(identifier, m_typeForName[identifier.toUpper()]); - } + Type t = m_index->typeFor(identifier); + QString desc=descriptionForIdentifier(identifier, t); KDevelop::IProject* p=KDevelop::ICore::self()->projectController()->findProjectForUrl(file); ICMakeManager* m=nullptr; if(p) m=p->managerPlugin()->extension(); if(m) { QPair entry = m->cacheValue(p, identifier); if(!entry.first.isEmpty()) desc += i18n("
Cache Value: %1\n", entry.first); if(!entry.second.isEmpty()) desc += i18n("
Cache Documentation: %1\n", entry.second); } if(desc.isEmpty()) return KDevelop::IDocumentation::Ptr(); else return KDevelop::IDocumentation::Ptr(new CMakeDoc(identifier, desc)); } KDevelop::IDocumentation::Ptr CMakeDocumentation::documentationForDeclaration(KDevelop::Declaration* decl) const { return description(decl->identifier().toString(), decl->url().toUrl()); } KDevelop::IDocumentation::Ptr CMakeDocumentation::documentationForIndex(const QModelIndex& idx) const { return description(idx.data().toString(), QUrl()); } QAbstractItemModel* CMakeDocumentation::indexModel() const { - initializeModel(); - return m_index; + return m_flatIndex; } QIcon CMakeDocumentation::icon() const { return QIcon::fromTheme("cmake"); } QString CMakeDocumentation::name() const { return QStringLiteral("CMake"); } KDevelop::IDocumentation::Ptr CMakeDocumentation::homePage() const { - if(m_typeForName.isEmpty()) - const_cast(this)->delayedInitialization(); -// initializeModel(); return KDevelop::IDocumentation::Ptr(new CMakeHomeDocumentation); } -void CMakeDocumentation::initializeModel() const -{ - if(!m_typeForName.isEmpty()) - return; - - QMetaObject::invokeMethod(const_cast(this), "delayedInitialization", Qt::QueuedConnection); -} - //////////CMakeDoc QWidget* CMakeDoc::documentationWidget(KDevelop::DocumentationFindWidget* findWidget, QWidget* parent) { KDevelop::StandardDocumentationView* view = new KDevelop::StandardDocumentationView(findWidget, parent); view->initZoom(provider()->name()); view->setHtml(mDesc); return view; } #include "cmakedocumentation.moc" diff --git a/projectmanagers/cmake/cmakedocumentation.h b/projectmanagers/cmake/cmakedocumentation.h index 5b1e5332e4..6fb53e3e39 100644 --- a/projectmanagers/cmake/cmakedocumentation.h +++ b/projectmanagers/cmake/cmakedocumentation.h @@ -1,71 +1,67 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKEDOCUMENTATION_H #define CMAKEDOCUMENTATION_H #include #include #include #include #include "icmakedocumentation.h" -class QStringListModel; namespace KDevelop { class Declaration; } class CMakeManager; class QUrl; +class CMakeCommandsContents; +class KDescendantsProxyModel; class CMakeDocumentation : public KDevelop::IPlugin, public ICMakeDocumentation { Q_OBJECT Q_INTERFACES( ICMakeDocumentation ) Q_INTERFACES( KDevelop::IDocumentationProvider ) public: explicit CMakeDocumentation( QObject* parent = nullptr, const QVariantList& args = QVariantList() ); KDevelop::IDocumentation::Ptr description(const QString& identifier, const QUrl &file) const override; KDevelop::IDocumentation::Ptr documentationForDeclaration(KDevelop::Declaration* declaration) const override; - QStringList names(Type t) const override; + QVector names(Type t) const override; + CMakeCommandsContents* model() const { return m_index; } QAbstractItemModel* indexModel() const override; KDevelop::IDocumentation::Ptr documentationForIndex(const QModelIndex& idx) const override; QIcon icon() const override; QString name() const override; KDevelop::IDocumentation::Ptr homePage() const override; QString descriptionForIdentifier(const QString& identifier, Type t) const; - public slots: - void delayedInitialization(); Q_SIGNALS: void addHistory(const KDevelop::IDocumentation::Ptr& doc) const override; private: - void initializeModel() const; - void collectIds(const QString& param, Type type); - - QMap m_typeForName; - const QString m_cmakeExecutable; - QStringListModel* m_index; + CMakeCommandsContents* m_index; + KDescendantsProxyModel* m_flatIndex; }; #endif // CMAKEDOCUMENTATION_H diff --git a/projectmanagers/cmake/cmakehelpdocumentation.cpp b/projectmanagers/cmake/cmakehelpdocumentation.cpp index 7a4cf8ca30..0014754201 100644 --- a/projectmanagers/cmake/cmakehelpdocumentation.cpp +++ b/projectmanagers/cmake/cmakehelpdocumentation.cpp @@ -1,112 +1,51 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakehelpdocumentation.h" #include #include #include "cmakedoc.h" #include "icmakedocumentation.h" #include "cmakedocumentation.h" +#include "cmakecommandscontents.h" #include #include #include - -static QString modules [] = { - i18n("Commands"), i18n("Variables"), i18n("Modules"), i18n("Properties"), i18n("Policies") -}; - -CMakeContentsModel::CMakeContentsModel(QObject* parent) - : QAbstractItemModel(parent) -{} +#include QString CMakeHomeDocumentation::name() const { return i18n("CMake Content Page"); } KDevelop::IDocumentationProvider* CMakeHomeDocumentation::provider() const { return CMakeDoc::s_provider; } QWidget* CMakeHomeDocumentation::documentationWidget(KDevelop::DocumentationFindWidget*, QWidget* parent) { QTreeView* contents=new QTreeView(parent); contents->header()->setVisible(false); - CMakeContentsModel* model=new CMakeContentsModel(contents); - contents->setModel(model); - QObject::connect(contents, &QTreeView::clicked, model, &CMakeContentsModel::showItem); + contents->setModel(CMakeDoc::s_provider->model()); + QObject::connect(contents, &QTreeView::clicked, CMakeDoc::s_provider->model(), &CMakeCommandsContents::showItemAt); return contents; } - -//Model methods implementation -QModelIndex CMakeContentsModel::parent(const QModelIndex& child) const -{ - if(child.isValid() && child.column()==0 && int(child.internalId())>=0) - return createIndex(child.internalId(),0, -1); - return QModelIndex(); -} - -QModelIndex CMakeContentsModel::index(int row, int column, const QModelIndex& parent) const -{ - if(row<0 || column!=0) - return QModelIndex(); - if(!parent.isValid() && row==ICMakeDocumentation::EOType) - return QModelIndex(); - - return createIndex(row,column, int(parent.isValid() ? parent.row() : -1)); -} - -int CMakeContentsModel::rowCount(const QModelIndex& parent) const -{ - if(!parent.isValid()) - return ICMakeDocumentation::EOType; - else if(int(parent.internalId())<0) { - int ss=CMakeDoc::s_provider->names((ICMakeDocumentation::Type) parent.row()).size(); - return ss; - } - return 0; -} - -QVariant CMakeContentsModel::data(const QModelIndex& index, int role) const -{ - if (index.isValid()) { - if(role==Qt::DisplayRole) { - int internal(index.internalId()); - if(internal>=0) - return CMakeDoc::s_provider->names((ICMakeDocumentation::Type) internal).at(index.row()); - else - return modules[index.row()]; - } - } - return QVariant(); -} - -void CMakeContentsModel::showItem(const QModelIndex& idx) -{ - if(idx.isValid() && int(idx.internalId())>=0) { - QString desc=CMakeDoc::s_provider->descriptionForIdentifier(idx.data().toString(), - (ICMakeDocumentation::Type) idx.parent().row()); - CMakeDoc::Ptr doc(new CMakeDoc(idx.data().toString(), desc)); - - KDevelop::ICore::self()->documentationController()->showDocumentation(doc); - } -} diff --git a/projectmanagers/cmake/cmakehelpdocumentation.h b/projectmanagers/cmake/cmakehelpdocumentation.h index b08be75194..6df7b90de3 100644 --- a/projectmanagers/cmake/cmakehelpdocumentation.h +++ b/projectmanagers/cmake/cmakehelpdocumentation.h @@ -1,53 +1,37 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKEHELPDOCUMENTATION_H #define CMAKEHELPDOCUMENTATION_H #include #include -class CMakeContentsModel : public QAbstractItemModel -{ - Q_OBJECT - public: - explicit CMakeContentsModel(QObject* parent) ; - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - - int columnCount(const QModelIndex&) const override { return 1; } - QModelIndex parent(const QModelIndex& child) const override; - - QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; - QVariant data(const QModelIndex& index, int role) const override; - public slots: - void showItem(const QModelIndex& idx); -}; - class CMakeHomeDocumentation : public KDevelop::IDocumentation { public: KDevelop::IDocumentationProvider* provider() const override; QString name() const override; QString description() const override { return name(); } QWidget* documentationWidget ( KDevelop::DocumentationFindWidget* findWidget, QWidget* parent = nullptr ) override; }; #endif