From ad13144cc0e2effa7752bfcdbdc4160da9dd825c Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 6 Oct 2023 23:49:27 +0200 Subject: [PATCH] CMakePM: Search after packages in CMAKE_PREFIX|MODULE_PATH This way code completion will have Qt6 package suggestions for find_packages. Change-Id: I9ab64425f850a0d990e77a559ce9f121bc9cf2d7 Reviewed-by: Alessandro Portale --- .../cmakefilecompletionassist.cpp | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp index 1ca5e5f23f7..57867e0974f 100644 --- a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp +++ b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp @@ -5,6 +5,8 @@ #include "cmakebuildsystem.h" #include "cmakebuildtarget.h" +#include "cmakebuildconfiguration.h" +#include "cmakeconfigitem.h" #include "cmakeprojectconstants.h" #include "cmaketool.h" #include "cmaketoolmanager.h" @@ -250,6 +252,71 @@ static QPair getLocalFunctionsAndVariables(const QByte return {functions, variables}; } +static QPair getFindAndConfigCMakePackages(const CMakeConfig &cmakeCache, + const Environment &environment) +{ + auto toFilePath = [](const QByteArray &str) -> FilePath { + return FilePath::fromUserInput(QString::fromUtf8(str)); + }; + + auto findPackageName = [](const QString &fileName) -> QString { + auto findIdx = fileName.indexOf("Find"); + auto endsWithCMakeIdx = fileName.lastIndexOf(".cmake"); + if (findIdx == 0 && endsWithCMakeIdx > 0) + return fileName.mid(4, endsWithCMakeIdx - 4); + return QString(); + }; + + auto configPackageName = [](const QString &fileName) -> QString { + auto configCMakeIdx = fileName.lastIndexOf("Config.cmake"); + if (configCMakeIdx > 0) + return fileName.left(configCMakeIdx); + auto dashConfigCMakeIdx = fileName.lastIndexOf("-config.cmake"); + if (dashConfigCMakeIdx > 0) + return fileName.left(dashConfigCMakeIdx); + return QString(); + }; + + QStringList modulePackages; + QStringList configPackages; + + struct + { + const QByteArray cmakeVariable; + const QString pathPrefix; + std::function function; + QStringList &result; + } mapping[] = {{"CMAKE_PREFIX_PATH", "lib/cmake", configPackageName, configPackages}, + {"CMAKE_MODULE_PATH", QString(), findPackageName, modulePackages}}; + + for (const auto &m : mapping) { + FilePaths paths = Utils::transform(cmakeCache.valueOf(m.cmakeVariable).split(';'), + toFilePath); + + paths << Utils::transform(environment.value(QString::fromUtf8(m.cmakeVariable)) + .split(";"), + &FilePath::fromUserInput); + + for (const auto &prefix : paths) { + // Only search for directories if we have a prefix + const FilePaths dirs = !m.pathPrefix.isEmpty() + ? prefix.pathAppended(m.pathPrefix) + .dirEntries({{"*"}, QDir::Dirs | QDir::NoDotAndDotDot}) + : FilePaths{prefix}; + const QStringList cmakeFiles + = Utils::transform(dirs, [](const FilePath &path) { + return Utils::transform(path.dirEntries({{"*.cmake"}, QDir::Files}, + QDir::Name), + &FilePath::fileName); + }); + m.result << Utils::transform(cmakeFiles, m.function); + } + m.result = Utils::filtered(m.result, std::not_fn(&QString::isEmpty)); + } + + return {modulePackages, configPackages}; +} + class PerformInputData { public: @@ -259,6 +326,8 @@ public: QStringList buildTargets; QStringList importedTargets; QStringList findPackageVariables; + CMakeConfig cmakeConfiguration; + Environment environment = Environment::systemEnvironment(); }; PerformInputData CMakeFileCompletionAssist::generatePerformInputData() const @@ -280,6 +349,8 @@ PerformInputData CMakeFileCompletionAssist::generatePerformInputData() const data.projectFunctions = projectKeywords.functions; data.importedTargets = bs->projectImportedTargets(); data.findPackageVariables = bs->projectFindPackageVariables(); + data.cmakeConfiguration = bs->configurationFromCMake(); + data.environment = bs->cmakeBuildConfiguration()->configureEnvironment(); } return data; @@ -323,6 +394,9 @@ IAssistProposal *CMakeFileCompletionAssist::doPerform(const PerformInputData &da auto [localFunctions, localVariables] = getLocalFunctionsAndVariables( interface()->textAt(0, prevFunctionEnd + 1).toUtf8()); + auto [findModules, configModules] = getFindAndConfigCMakePackages(data.cmakeConfiguration, + data.environment); + QList items; const QString varGenexToken = interface()->textAt(startPos - 2, 2); @@ -375,8 +449,11 @@ IAssistProposal *CMakeFileCompletionAssist::doPerform(const PerformInputData &da if (functionName == "include" && !onlyFileItems()) items.append(generateList(data.keywords.includeStandardModules, m_moduleIcon)); - if (functionName == "find_package") + if (functionName == "find_package") { items.append(generateList(data.keywords.findModules, m_moduleIcon)); + items.append(generateList(findModules, m_moduleIcon)); + items.append(generateList(configModules, m_moduleIcon)); + } if ((functionName.contains("target") || functionName == "install" || functionName == "add_dependencies" || functionName == "set_property"