Warning, file /kdevelop/kdevelop/plugins/custom-definesandincludes/noprojectincludesanddefines/noprojectincludepathsmanager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2014 Sergey Kalinichev <kalinichev.so.0@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "noprojectincludepathsmanager.h"
0008 
0009 #include <QFile>
0010 #include <QDir>
0011 #include <QFileInfo>
0012 
0013 #include <KLocalizedString>
0014 
0015 #include <interfaces/icore.h>
0016 #include <interfaces/ilanguagecontroller.h>
0017 #include <language/backgroundparser/backgroundparser.h>
0018 #include <serialization/indexedstring.h>
0019 
0020 #include "noprojectcustomincludepaths.h"
0021 
0022 namespace
0023 {
0024 inline QString includePathsFile() { return QStringLiteral(".kdev_include_paths"); }
0025 
0026 
0027 bool removeSettings(const QString& storageDirectory)
0028 {
0029     const QString file = storageDirectory + QDir::separator() + includePathsFile();
0030     return QFile::remove(file);
0031 }
0032 
0033 QStringList pathListToStringList(const Path::List& paths)
0034 {
0035     QStringList sl;
0036     sl.reserve(paths.size());
0037     for (const auto& p : paths) {
0038         sl << p.path();
0039     }
0040     return sl;
0041 }
0042 }
0043 
0044 QString NoProjectIncludePathsManager::findConfigurationFile(const QString& path)
0045 {
0046     QDir dir(path);
0047     while (dir.exists()) {
0048         QFileInfo customIncludePathsFile(dir, includePathsFile());
0049         if (customIncludePathsFile.exists()) {
0050             return customIncludePathsFile.absoluteFilePath();
0051         }
0052 
0053         if (!dir.cdUp()) {
0054             break;
0055         }
0056     }
0057     return {};
0058 }
0059 
0060 std::pair<Path::List, QHash<QString, QString>> 
0061     NoProjectIncludePathsManager::includesAndDefines(const QString& path)
0062 {
0063     QFileInfo fi(path);
0064 
0065     auto pathToFile = findConfigurationFile(fi.absoluteDir().absolutePath());
0066     if (pathToFile.isEmpty()) {
0067         return {};
0068     }
0069     Path::List includes;
0070     QHash<QString, QString> defines;
0071 
0072     QFile f(pathToFile);
0073     if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
0074         const QString fileContent = QString::fromLocal8Bit(f.readAll());
0075         const auto lines = fileContent.splitRef(QLatin1Char('\n'), Qt::SkipEmptyParts);
0076         QFileInfo dir(pathToFile);
0077         const QChar dirSeparator = QDir::separator();
0078         for (const auto& line : lines) {
0079             const auto textLine = line.trimmed().toString();
0080             if (textLine.startsWith(QLatin1String("#define "))) {
0081                 QStringList items = textLine.split(QLatin1Char(' '));
0082                 if (items.length() > 1)
0083                 {
0084                     defines[items[1]] = QStringList(items.mid(2)).join(QLatin1Char(' '));
0085                 }else{
0086                     qWarning() << i18n("Bad #define directive in %1: %2", pathToFile, textLine);
0087                 }
0088                 continue;
0089             }
0090             if (!textLine.isEmpty()) {
0091                 QFileInfo pathInfo(textLine);
0092                 if (pathInfo.isRelative()) {
0093                     includes << Path(dir.canonicalPath() + dirSeparator + textLine);
0094                 } else {
0095                     includes << Path(textLine);
0096                 }
0097             }
0098         }
0099         f.close();
0100     }
0101     return std::make_pair(includes, defines);
0102 }
0103 
0104 bool NoProjectIncludePathsManager::writeIncludePaths(const QString& storageDirectory, const QStringList& includePaths)
0105 {
0106     QDir dir(storageDirectory);
0107     QFileInfo customIncludePaths(dir, includePathsFile());
0108     QFile f(customIncludePaths.filePath());
0109     if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
0110         QTextStream out(&f);
0111         for (const auto& customPath : includePaths) {
0112             out << customPath << QLatin1Char('\n');
0113         }
0114         if (includePaths.isEmpty()) {
0115             removeSettings(storageDirectory);
0116         }
0117         return true;
0118     } else {
0119         return false;
0120     }
0121 }
0122 
0123 void NoProjectIncludePathsManager::openConfigurationDialog(const QString& path)
0124 {
0125     auto cip = new NoProjectCustomIncludePaths;
0126     cip->setAttribute(Qt::WA_DeleteOnClose);
0127     cip->setModal(true);
0128 
0129     QFileInfo fi(path);
0130     auto dir = fi.absoluteDir().absolutePath();
0131     cip->setStorageDirectory(dir);
0132 
0133     auto paths = includesAndDefines(path).first;
0134 
0135     cip->setCustomIncludePaths(pathListToStringList(paths));
0136 
0137     QObject::connect(cip, &QDialog::accepted, cip, [this, cip, &path]() {
0138         if (!writeIncludePaths(cip->storageDirectory(), cip->customIncludePaths())) {
0139             qWarning() << i18n("Failed to save custom include paths in directory: %1", cip->storageDirectory());
0140         }
0141         KDevelop::ICore::self()->languageController()->backgroundParser()->addDocument(KDevelop::IndexedString(path));
0142     });
0143 }