forked from qt-creator/qt-creator
CMakePM: Display help details for code completion
The first 1024 bytes from the CMake .rst files are displayed raw data. A .rst to html or markdown would be needed for nicer user experience. Change-Id: Ie6adbb404d844ae88b868b465d4125c2177e6cfe Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -1278,9 +1278,9 @@ void CMakeBuildSystem::setupCMakeSymbolsHash()
|
|||||||
m_cmakeSymbolsHash.insert(QString::fromUtf8(arg.Value), link);
|
m_cmakeSymbolsHash.insert(QString::fromUtf8(arg.Value), link);
|
||||||
|
|
||||||
if (func.LowerCaseName() == "option")
|
if (func.LowerCaseName() == "option")
|
||||||
m_projectKeywords.variables << QString::fromUtf8(arg.Value);
|
m_projectKeywords.variables[QString::fromUtf8(arg.Value)] = FilePath();
|
||||||
else
|
else
|
||||||
m_projectKeywords.functions << QString::fromUtf8(arg.Value);
|
m_projectKeywords.functions[QString::fromUtf8(arg.Value)] = FilePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,38 @@ QList<AssistProposalItemInterface *> generateList(const T &words, const QIcon &i
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString readFirstParagraphs(const QString &element, const FilePath &helpFile)
|
||||||
|
{
|
||||||
|
auto content = helpFile.fileContents(1024).value_or(QByteArray());
|
||||||
|
return QString("```\n%1\n```").arg(QString::fromUtf8(content.left(content.lastIndexOf("\n"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<AssistProposalItemInterface *> generateList(const QMap<QString, FilePath> &words,
|
||||||
|
const QIcon &icon)
|
||||||
|
{
|
||||||
|
static QMap<FilePath, QString> map;
|
||||||
|
struct MarkDownAssitProposalItem : public AssistProposalItem
|
||||||
|
{
|
||||||
|
Qt::TextFormat detailFormat() const { return Qt::MarkdownText; }
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<AssistProposalItemInterface *> list;
|
||||||
|
for (const auto &[text, helpFile] : words.asKeyValueRange()) {
|
||||||
|
MarkDownAssitProposalItem *item = new MarkDownAssitProposalItem();
|
||||||
|
item->setText(text);
|
||||||
|
|
||||||
|
if (!helpFile.isEmpty()) {
|
||||||
|
if (!map.contains(helpFile))
|
||||||
|
map[helpFile] = readFirstParagraphs(text, helpFile);
|
||||||
|
item->setDetail(map.value(helpFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
item->setIcon(icon);
|
||||||
|
list << item;
|
||||||
|
};
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
static int addFilePathItems(const AssistInterface *interface,
|
static int addFilePathItems(const AssistInterface *interface,
|
||||||
QList<AssistProposalItemInterface *> &items,
|
QList<AssistProposalItemInterface *> &items,
|
||||||
int symbolStartPos)
|
int symbolStartPos)
|
||||||
|
|||||||
@@ -89,19 +89,8 @@ public:
|
|||||||
bool m_didRun = true;
|
bool m_didRun = true;
|
||||||
|
|
||||||
QList<CMakeTool::Generator> m_generators;
|
QList<CMakeTool::Generator> m_generators;
|
||||||
QMap<QString, QStringList> m_functionArgs;
|
CMakeKeywords m_keywords;
|
||||||
QVector<FileApi> m_fileApis;
|
QVector<FileApi> m_fileApis;
|
||||||
QStringList m_variables;
|
|
||||||
QStringList m_functions;
|
|
||||||
QStringList m_properties;
|
|
||||||
QStringList m_generatorExpressions;
|
|
||||||
QStringList m_directoryProperties;
|
|
||||||
QStringList m_sourceProperties;
|
|
||||||
QStringList m_targetProperties;
|
|
||||||
QStringList m_testProperties;
|
|
||||||
QStringList m_includeStandardModules;
|
|
||||||
QStringList m_findModules;
|
|
||||||
QStringList m_policies;
|
|
||||||
CMakeTool::Version m_version;
|
CMakeTool::Version m_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -260,7 +249,7 @@ CMakeKeywords CMakeTool::keywords()
|
|||||||
if (!isValid())
|
if (!isValid())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
if (m_introspection->m_functions.isEmpty() && m_introspection->m_didRun) {
|
if (m_introspection->m_keywords.functions.isEmpty() && m_introspection->m_didRun) {
|
||||||
Process proc;
|
Process proc;
|
||||||
|
|
||||||
const FilePath findCMakeRoot = TemporaryDirectory::masterDirectoryFilePath()
|
const FilePath findCMakeRoot = TemporaryDirectory::masterDirectoryFilePath()
|
||||||
@@ -279,61 +268,52 @@ CMakeKeywords CMakeTool::keywords()
|
|||||||
const struct
|
const struct
|
||||||
{
|
{
|
||||||
const QString helpPath;
|
const QString helpPath;
|
||||||
QStringList &targetList;
|
QMap<QString, FilePath> &targetMap;
|
||||||
} introspections[] = {
|
} introspections[] = {
|
||||||
// Functions
|
// Functions
|
||||||
{"Help/command", m_introspection->m_functions},
|
{"Help/command", m_introspection->m_keywords.functions},
|
||||||
// Properties
|
// Properties
|
||||||
{"Help/prop_dir", m_introspection->m_directoryProperties},
|
{"Help/prop_dir", m_introspection->m_keywords.directoryProperties},
|
||||||
{"Help/prop_sf", m_introspection->m_sourceProperties},
|
{"Help/prop_sf", m_introspection->m_keywords.sourceProperties},
|
||||||
{"Help/prop_test", m_introspection->m_testProperties},
|
{"Help/prop_test", m_introspection->m_keywords.testProperties},
|
||||||
{"Help/prop_tgt", m_introspection->m_targetProperties},
|
{"Help/prop_tgt", m_introspection->m_keywords.targetProperties},
|
||||||
{"Help/prop_gbl", m_introspection->m_properties},
|
{"Help/prop_gbl", m_introspection->m_keywords.properties},
|
||||||
// Variables
|
// Variables
|
||||||
{"Help/variable", m_introspection->m_variables},
|
{"Help/variable", m_introspection->m_keywords.variables},
|
||||||
// Policies
|
// Policies
|
||||||
{"Help/policy", m_introspection->m_policies},
|
{"Help/policy", m_introspection->m_keywords.policies},
|
||||||
};
|
};
|
||||||
for (auto &i : introspections) {
|
for (auto &i : introspections) {
|
||||||
const FilePaths files = cmakeRoot.pathAppended(i.helpPath)
|
const FilePaths files = cmakeRoot.pathAppended(i.helpPath)
|
||||||
.dirEntries({{"*.rst"}, QDir::Files}, QDir::Name);
|
.dirEntries({{"*.rst"}, QDir::Files}, QDir::Name);
|
||||||
i.targetList = transform<QStringList>(files, &FilePath::completeBaseName);
|
for (const auto &filePath : files)
|
||||||
|
i.targetMap[filePath.completeBaseName()] = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_introspection->m_properties << m_introspection->m_directoryProperties;
|
for (const auto &map : {m_introspection->m_keywords.directoryProperties,
|
||||||
m_introspection->m_properties << m_introspection->m_sourceProperties;
|
m_introspection->m_keywords.sourceProperties,
|
||||||
m_introspection->m_properties << m_introspection->m_testProperties;
|
m_introspection->m_keywords.testProperties,
|
||||||
m_introspection->m_properties << m_introspection->m_targetProperties;
|
m_introspection->m_keywords.targetProperties}) {
|
||||||
|
m_introspection->m_keywords.properties.insert(map);
|
||||||
|
}
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
const FilePaths files
|
const FilePaths files
|
||||||
= cmakeRoot.pathAppended("Help/module").dirEntries({{"*.rst"}, QDir::Files}, QDir::Name);
|
= cmakeRoot.pathAppended("Help/module").dirEntries({{"*.rst"}, QDir::Files}, QDir::Name);
|
||||||
const QStringList fileNames = transform<QStringList>(files, &FilePath::completeBaseName);
|
for (const FilePath &filePath : files) {
|
||||||
for (const QString &fileName : fileNames) {
|
const QString fileName = filePath.completeBaseName();
|
||||||
if (fileName.startsWith("Find"))
|
if (fileName.startsWith("Find"))
|
||||||
m_introspection->m_findModules << fileName.mid(4);
|
m_introspection->m_keywords.findModules[fileName.mid(4)] = filePath;
|
||||||
else
|
else
|
||||||
m_introspection->m_includeStandardModules << fileName;
|
m_introspection->m_keywords.includeStandardModules[fileName] = filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseSyntaxHighlightingXml();
|
const QStringList moduleFunctions = parseSyntaxHighlightingXml();
|
||||||
|
for (const auto &function : moduleFunctions)
|
||||||
|
m_introspection->m_keywords.functions[function] = FilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
CMakeKeywords keywords;
|
return m_introspection->m_keywords;
|
||||||
keywords.functions = Utils::toSet(m_introspection->m_functions);
|
|
||||||
keywords.variables = Utils::toSet(m_introspection->m_variables);
|
|
||||||
keywords.functionArgs = m_introspection->m_functionArgs;
|
|
||||||
keywords.properties = Utils::toSet(m_introspection->m_properties);
|
|
||||||
keywords.generatorExpressions = Utils::toSet(m_introspection->m_generatorExpressions);
|
|
||||||
keywords.directoryProperties = Utils::toSet(m_introspection->m_directoryProperties);
|
|
||||||
keywords.sourceProperties = Utils::toSet(m_introspection->m_sourceProperties);
|
|
||||||
keywords.targetProperties = Utils::toSet(m_introspection->m_targetProperties);
|
|
||||||
keywords.testProperties = Utils::toSet(m_introspection->m_testProperties);
|
|
||||||
keywords.includeStandardModules = Utils::toSet(m_introspection->m_includeStandardModules);
|
|
||||||
keywords.findModules = Utils::toSet(m_introspection->m_findModules);
|
|
||||||
keywords.policies = Utils::toSet(m_introspection->m_policies);
|
|
||||||
|
|
||||||
return keywords;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMakeTool::hasFileApi(bool ignoreCache) const
|
bool CMakeTool::hasFileApi(bool ignoreCache) const
|
||||||
@@ -495,8 +475,6 @@ static QStringList parseDefinition(const QString &definition)
|
|||||||
|
|
||||||
void CMakeTool::parseFunctionDetailsOutput(const QString &output)
|
void CMakeTool::parseFunctionDetailsOutput(const QString &output)
|
||||||
{
|
{
|
||||||
const QSet<QString> functionSet = Utils::toSet(m_introspection->m_functions);
|
|
||||||
|
|
||||||
bool expectDefinition = false;
|
bool expectDefinition = false;
|
||||||
QString currentDefinition;
|
QString currentDefinition;
|
||||||
|
|
||||||
@@ -515,14 +493,15 @@ void CMakeTool::parseFunctionDetailsOutput(const QString &output)
|
|||||||
QStringList words = parseDefinition(currentDefinition);
|
QStringList words = parseDefinition(currentDefinition);
|
||||||
if (!words.isEmpty()) {
|
if (!words.isEmpty()) {
|
||||||
const QString command = words.takeFirst();
|
const QString command = words.takeFirst();
|
||||||
if (functionSet.contains(command)) {
|
if (m_introspection->m_keywords.functions.contains(command)) {
|
||||||
const QStringList tmp = Utils::sorted(
|
const QStringList tmp = Utils::sorted(
|
||||||
words + m_introspection->m_functionArgs[command]);
|
words + m_introspection->m_keywords.functionArgs[command]);
|
||||||
m_introspection->m_functionArgs[command] = Utils::filteredUnique(tmp);
|
m_introspection->m_keywords.functionArgs[command] = Utils::filteredUnique(
|
||||||
|
tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!words.isEmpty() && functionSet.contains(words.at(0)))
|
if (!words.isEmpty() && m_introspection->m_keywords.functions.contains(words.at(0)))
|
||||||
m_introspection->m_functionArgs[words.at(0)];
|
m_introspection->m_keywords.functionArgs[words.at(0)];
|
||||||
currentDefinition.clear();
|
currentDefinition.clear();
|
||||||
} else {
|
} else {
|
||||||
currentDefinition.append(line.trimmed() + ' ');
|
currentDefinition.append(line.trimmed() + ' ');
|
||||||
@@ -560,9 +539,9 @@ QStringList CMakeTool::parseVariableOutput(const QString &output)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::parseSyntaxHighlightingXml()
|
QStringList CMakeTool::parseSyntaxHighlightingXml()
|
||||||
{
|
{
|
||||||
QSet<QString> functionSet = Utils::toSet(m_introspection->m_functions);
|
QStringList moduleFunctions;
|
||||||
|
|
||||||
const FilePath cmakeXml = Core::ICore::resourcePath("generic-highlighter/syntax/cmake.xml");
|
const FilePath cmakeXml = Core::ICore::resourcePath("generic-highlighter/syntax/cmake.xml");
|
||||||
QXmlStreamReader reader(cmakeXml.fileContents().value_or(QByteArray()));
|
QXmlStreamReader reader(cmakeXml.fileContents().value_or(QByteArray()));
|
||||||
@@ -588,19 +567,19 @@ void CMakeTool::parseSyntaxHighlightingXml()
|
|||||||
const auto functionName = name.left(name.length() - 6);
|
const auto functionName = name.left(name.length() - 6);
|
||||||
QStringList arguments = readItemList(reader);
|
QStringList arguments = readItemList(reader);
|
||||||
|
|
||||||
if (m_introspection->m_functionArgs.contains(functionName))
|
if (m_introspection->m_keywords.functionArgs.contains(functionName))
|
||||||
arguments.append(m_introspection->m_functionArgs.value(functionName));
|
arguments.append(
|
||||||
|
m_introspection->m_keywords.functionArgs.value(functionName));
|
||||||
|
|
||||||
m_introspection->m_functionArgs[functionName] = arguments;
|
m_introspection->m_keywords.functionArgs[functionName] = arguments;
|
||||||
|
|
||||||
// Functions that are part of CMake modules like ExternalProject_Add
|
// Functions that are part of CMake modules like ExternalProject_Add
|
||||||
// which are not reported by cmake --help-list-commands
|
// which are not reported by cmake --help-list-commands
|
||||||
if (!functionSet.contains(functionName)) {
|
if (!m_introspection->m_keywords.functions.contains(functionName)) {
|
||||||
functionSet.insert(functionName);
|
moduleFunctions << functionName;
|
||||||
m_introspection->m_functions.append(functionName);
|
|
||||||
}
|
}
|
||||||
} else if (name == u"generator-expressions") {
|
} else if (name == u"generator-expressions") {
|
||||||
m_introspection->m_generatorExpressions = readItemList(reader);
|
m_introspection->m_keywords.generatorExpressions = toSet(readItemList(reader));
|
||||||
} else {
|
} else {
|
||||||
reader.skipCurrentElement();
|
reader.skipCurrentElement();
|
||||||
}
|
}
|
||||||
@@ -623,16 +602,19 @@ void CMakeTool::parseSyntaxHighlightingXml()
|
|||||||
{"set_target_properties", "set_directory_properties"},
|
{"set_target_properties", "set_directory_properties"},
|
||||||
{"set_tests_properties", "set_directory_properties"}};
|
{"set_tests_properties", "set_directory_properties"}};
|
||||||
for (const auto &pair : std::as_const(functionPairs)) {
|
for (const auto &pair : std::as_const(functionPairs)) {
|
||||||
if (!m_introspection->m_functionArgs.contains(pair.first))
|
if (!m_introspection->m_keywords.functionArgs.contains(pair.first))
|
||||||
m_introspection->m_functionArgs[pair.first] = m_introspection->m_functionArgs.value(
|
m_introspection->m_keywords.functionArgs[pair.first]
|
||||||
pair.second);
|
= m_introspection->m_keywords.functionArgs.value(pair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case for cmake_print_variables, which will print the names and values for variables
|
// Special case for cmake_print_variables, which will print the names and values for variables
|
||||||
// and needs to be as a known function
|
// and needs to be as a known function
|
||||||
const QString cmakePrintVariables("cmake_print_variables");
|
const QString cmakePrintVariables("cmake_print_variables");
|
||||||
m_introspection->m_functionArgs[cmakePrintVariables] = {};
|
m_introspection->m_keywords.functionArgs[cmakePrintVariables] = {};
|
||||||
m_introspection->m_functions.append(cmakePrintVariables);
|
moduleFunctions << cmakePrintVariables;
|
||||||
|
|
||||||
|
moduleFunctions.removeDuplicates();
|
||||||
|
return moduleFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMakeTool::fetchFromCapabilities(bool ignoreCache) const
|
void CMakeTool::fetchFromCapabilities(bool ignoreCache) const
|
||||||
|
|||||||
@@ -21,17 +21,17 @@ namespace Internal { class IntrospectionData; }
|
|||||||
|
|
||||||
struct CMAKE_EXPORT CMakeKeywords
|
struct CMAKE_EXPORT CMakeKeywords
|
||||||
{
|
{
|
||||||
QSet<QString> variables;
|
QMap<QString, Utils::FilePath> variables;
|
||||||
QSet<QString> functions;
|
QMap<QString, Utils::FilePath> functions;
|
||||||
QSet<QString> properties;
|
QMap<QString, Utils::FilePath> properties;
|
||||||
QSet<QString> generatorExpressions;
|
QSet<QString> generatorExpressions;
|
||||||
QSet<QString> directoryProperties;
|
QMap<QString, Utils::FilePath> directoryProperties;
|
||||||
QSet<QString> sourceProperties;
|
QMap<QString, Utils::FilePath> sourceProperties;
|
||||||
QSet<QString> targetProperties;
|
QMap<QString, Utils::FilePath> targetProperties;
|
||||||
QSet<QString> testProperties;
|
QMap<QString, Utils::FilePath> testProperties;
|
||||||
QSet<QString> includeStandardModules;
|
QMap<QString, Utils::FilePath> includeStandardModules;
|
||||||
QSet<QString> findModules;
|
QMap<QString, Utils::FilePath> findModules;
|
||||||
QSet<QString> policies;
|
QMap<QString, Utils::FilePath> policies;
|
||||||
QMap<QString, QStringList> functionArgs;
|
QMap<QString, QStringList> functionArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ private:
|
|||||||
void runCMake(Utils::Process &proc, const QStringList &args, int timeoutS = 1) const;
|
void runCMake(Utils::Process &proc, const QStringList &args, int timeoutS = 1) const;
|
||||||
void parseFunctionDetailsOutput(const QString &output);
|
void parseFunctionDetailsOutput(const QString &output);
|
||||||
QStringList parseVariableOutput(const QString &output);
|
QStringList parseVariableOutput(const QString &output);
|
||||||
void parseSyntaxHighlightingXml();
|
QStringList parseSyntaxHighlightingXml();
|
||||||
|
|
||||||
void fetchFromCapabilities(bool ignoreCache = false) const;
|
void fetchFromCapabilities(bool ignoreCache = false) const;
|
||||||
void parseFromCapabilities(const QString &input) const;
|
void parseFromCapabilities(const QString &input) const;
|
||||||
|
|||||||
Reference in New Issue
Block a user