diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp index 6ba35180c31..1f1e873be52 100644 --- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp @@ -9,6 +9,7 @@ #include "cmakefilecompletionassist.h" #include "cmakeindenter.h" #include "cmakekitaspect.h" +#include "cmakeproject.h" #include "cmakeprojectconstants.h" #include "3rdparty/cmake/cmListFileCache.h" @@ -19,11 +20,14 @@ #include #include #include +#include #include #include +#include #include #include #include +#include #include @@ -31,6 +35,7 @@ using namespace Core; using namespace ProjectExplorer; +using namespace Utils; using namespace TextEditor; namespace CMakeProjectManager::Internal { @@ -308,6 +313,83 @@ static TextDocument *createCMakeDocument() return doc; } +// +// CMakeHoverHandler +// + +class CMakeHoverHandler : public TextEditor::BaseHoverHandler +{ + mutable CMakeKeywords m_keywords; + QString m_helpToolTip; + +public: + const CMakeKeywords &keywords() const; + + void identifyMatch(TextEditor::TextEditorWidget *editorWidget, + int pos, + ReportPriority report) final; + void operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) final; +}; + +const CMakeKeywords &CMakeHoverHandler::keywords() const +{ + if (m_keywords.functions.isEmpty()) { + CMakeTool *tool = nullptr; + if (auto bs = ProjectTree::currentBuildSystem()) + tool = CMakeKitAspect::cmakeTool(bs->target()->kit()); + if (!tool) + tool = CMakeToolManager::defaultCMakeTool(); + + if (tool) + m_keywords = tool->keywords(); + } + + return m_keywords; +} + +QString readFirstParagraphs(const QString &element, const FilePath &helpFile); + +void CMakeHoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, + int pos, + ReportPriority report) +{ + const QScopeGuard cleanup([this, report] { report(priority()); }); + + QTextCursor cursor = editorWidget->textCursor(); + cursor.setPosition(pos); + const QString word = Utils::Text::wordUnderCursor(cursor); + + FilePath helpFile; + for (const auto &map : {keywords().functions, + keywords().variables, + keywords().directoryProperties, + keywords().sourceProperties, + keywords().targetProperties, + keywords().testProperties, + keywords().properties, + keywords().includeStandardModules, + keywords().findModules, + keywords().policies}) { + if (map.contains(word)) { + helpFile = map.value(word); + break; + } + } + m_helpToolTip.clear(); + if (!helpFile.isEmpty()) + m_helpToolTip = readFirstParagraphs(word, helpFile); + + setPriority(m_helpToolTip.isEmpty() ? Priority_Tooltip : Priority_None); +} + +void CMakeHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point) +{ + if (!m_helpToolTip.isEmpty()) + Utils::ToolTip::show(point, m_helpToolTip, Qt::MarkdownText, editorWidget); + else + Utils::ToolTip::hide(); +} + // // CMakeEditorFactory // @@ -334,6 +416,8 @@ CMakeEditorFactory::CMakeEditorFactory() | TextEditorActionHandler::FollowSymbolUnderCursor | TextEditorActionHandler::Format); + addHoverHandler(new CMakeHoverHandler); + ActionContainer *contextMenu = ActionManager::createMenu(Constants::M_CONTEXT); contextMenu->addAction(ActionManager::command(TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR)); contextMenu->addSeparator(Context(Constants::CMAKE_EDITOR_ID)); diff --git a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp index a2ba8b3a604..339a11b64ae 100644 --- a/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp +++ b/src/plugins/cmakeprojectmanager/cmakefilecompletionassist.cpp @@ -155,14 +155,21 @@ QList generateList(const T &words, const QIcon &i QString readFirstParagraphs(const QString &element, const FilePath &helpFile) { + static QMap map; + if (map.contains(helpFile)) + return map.value(helpFile); + auto content = helpFile.fileContents(1024).value_or(QByteArray()); - return QString("```\n%1\n```").arg(QString::fromUtf8(content.left(content.lastIndexOf("\n")))); + const QString firstParagraphs + = QString("```\n%1\n```").arg(QString::fromUtf8(content.left(content.lastIndexOf("\n")))); + + map[helpFile] = firstParagraphs; + return firstParagraphs; } QList generateList(const QMap &words, const QIcon &icon) { - static QMap map; struct MarkDownAssitProposalItem : public AssistProposalItem { Qt::TextFormat detailFormat() const { return Qt::MarkdownText; } @@ -172,13 +179,8 @@ QList generateList(const QMap 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)); - } - + if (!helpFile.isEmpty()) + item->setDetail(readFirstParagraphs(text, helpFile)); item->setIcon(icon); list << item; };