diff options
author | Eike Ziller <eike.ziller@qt.io> | 2018-01-25 15:51:36 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-01-21 10:30:03 +0000 |
commit | 6c10d36f8776900f75f16ae26a127e4771eda1e6 (patch) | |
tree | e2932ae96fd5a2ca0e3d84a5ef818bf16704fb36 /src/plugins/clangcodemodel/clanghoverhandler.cpp | |
parent | 2d8bc0e509a5dbb7314ea12eeb7a28acc13d82cd (diff) | |
download | qt-creator-6c10d36f8776900f75f16ae26a127e4771eda1e6.tar.gz |
Try harder to get context help in presence of diagnostics
- even if there are diagnostics still try to retrieve symbol info
and help
- fall back to text based keyword extraction in case code model
info fails
- if both a code model tool tip (e.g. function signature or type)
and help are available, show both
Task-number: QTCREATORBUG-15959
Change-Id: Id85a223c24849ead1b25d63776d64a7da1cc73ef
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
Diffstat (limited to 'src/plugins/clangcodemodel/clanghoverhandler.cpp')
-rw-r--r-- | src/plugins/clangcodemodel/clanghoverhandler.cpp | 115 |
1 files changed, 90 insertions, 25 deletions
diff --git a/src/plugins/clangcodemodel/clanghoverhandler.cpp b/src/plugins/clangcodemodel/clanghoverhandler.cpp index be59805170..1dc294cab5 100644 --- a/src/plugins/clangcodemodel/clanghoverhandler.cpp +++ b/src/plugins/clangcodemodel/clanghoverhandler.cpp @@ -28,6 +28,7 @@ #include <coreplugin/helpmanager.h> #include <cpptools/baseeditordocumentprocessor.h> #include <cpptools/cppmodelmanager.h> +#include <cpptools/cpptoolsreuse.h> #include <cpptools/editordocumenthandle.h> #include <texteditor/texteditor.h> @@ -37,6 +38,7 @@ #include <QFutureWatcher> #include <QLoggingCategory> +#include <QRegularExpression> #include <QTextCodec> #include <QVBoxLayout> @@ -105,6 +107,79 @@ ClangHoverHandler::~ClangHoverHandler() abort(); } +static int skipChars(QTextCursor *tc, + QTextCursor::MoveOperation op, + int offset, + std::function<bool(const QChar &)> skip) +{ + const QTextDocument *doc = tc->document(); + QChar ch = doc->characterAt(tc->position() + offset); + if (ch.isNull()) + return 0; + int count = 0; + while (skip(ch)) { + if (tc->movePosition(op)) + ++count; + else + break; + ch = doc->characterAt(tc->position() + offset); + } + return count; +} + +static int skipCharsForward(QTextCursor *tc, std::function<bool(const QChar &)> skip) +{ + return skipChars(tc, QTextCursor::NextCharacter, 0, skip); +} + +static int skipCharsBackward(QTextCursor *tc, std::function<bool(const QChar &)> skip) +{ + return skipChars(tc, QTextCursor::PreviousCharacter, -1, skip); +} + +static QStringList fallbackWords(QTextDocument *document, int pos) +{ + const auto isSpace = [](const QChar &c) { return c.isSpace(); }; + const auto isColon = [](const QChar &c) { return c == ':'; }; + const auto isValidIdentifierChar = [document](const QTextCursor &tc) { + return CppTools::isValidIdentifierChar(document->characterAt(tc.position())); + }; + // move to the end + QTextCursor endCursor(document); + endCursor.setPosition(pos); + do { + CppTools::moveCursorToEndOfIdentifier(&endCursor); + // possibly skip :: + QTextCursor temp(endCursor); + skipCharsForward(&temp, isSpace); + const int colons = skipCharsForward(&temp, isColon); + skipCharsForward(&temp, isSpace); + if (colons == 2 && isValidIdentifierChar(temp)) + endCursor = temp; + } while (isValidIdentifierChar(endCursor)); + + QStringList results; + QTextCursor startCursor(endCursor); + do { + CppTools::moveCursorToStartOfIdentifier(&startCursor); + if (startCursor.position() == endCursor.position()) + break; + QTextCursor temp(endCursor); + temp.setPosition(startCursor.position(), QTextCursor::KeepAnchor); + results.append(temp.selectedText().remove(QRegularExpression("\\s"))); + // possibly skip :: + temp = startCursor; + skipCharsBackward(&temp, isSpace); + const int colons = skipCharsBackward(&temp, isColon); + skipCharsBackward(&temp, isSpace); + if (colons == 2 + && CppTools::isValidIdentifierChar(document->characterAt(temp.position() - 1))) { + startCursor = temp; + } + } while (!isValidIdentifierChar(startCursor)); + return results; +} + void ClangHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos, BaseHoverHandler::ReportPriority report) @@ -118,8 +193,6 @@ void ClangHoverHandler::identifyMatch(TextEditorWidget *editorWidget, qCDebug(hoverLog) << "Checking for diagnostic at" << pos; setPriority(Priority_Diagnostic); m_cursorPosition = pos; - report(priority()); - return; } // Check for tooltips (async) @@ -128,17 +201,25 @@ void ClangHoverHandler::identifyMatch(TextEditorWidget *editorWidget, qCDebug(hoverLog) << "Requesting tooltip info at" << pos; m_reportPriority = report; m_futureWatcher.reset(new QFutureWatcher<CppTools::ToolTipInfo>()); - QObject::connect(m_futureWatcher.data(), &QFutureWatcherBase::finished, [this]() { - if (m_futureWatcher->isCanceled()) - m_reportPriority(Priority_None); - else - processToolTipInfo(m_futureWatcher->result()); - }); + const QStringList fallback = fallbackWords(editorWidget->document(), pos); + QObject::connect(m_futureWatcher.data(), + &QFutureWatcherBase::finished, + [this, fallback]() { + if (m_futureWatcher->isCanceled()) { + m_reportPriority(Priority_None); + } else { + CppTools::ToolTipInfo info = m_futureWatcher->result(); + qCDebug(hoverLog) + << "Appending word-based fallback lookup" << fallback; + info.qDocIdCandidates += fallback; + processToolTipInfo(info); + } + }); m_futureWatcher->setFuture(future); return; } - report(Priority_None); // Ops, something went wrong. + report(priority()); // Ops, something went wrong. } void ClangHoverHandler::abort() @@ -198,22 +279,6 @@ void ClangHoverHandler::processToolTipInfo(const CppTools::ToolTipInfo &info) m_reportPriority(priority()); } -void ClangHoverHandler::decorateToolTip() -{ - if (priority() == Priority_Diagnostic) - return; - - if (Qt::mightBeRichText(toolTip())) - setToolTip(toolTip().toHtmlEscaped()); - - const HelpItem &help = lastHelpItemIdentified(); - if (help.isValid()) { - const QString text = CppTools::CppHoverHandler::tooltipTextForHelpItem(help); - if (!text.isEmpty()) - setToolTip(text); - } -} - void ClangHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) { |