diff options
author | David Schulz <david.schulz@qt.io> | 2019-05-15 11:19:31 +0200 |
---|---|---|
committer | David Schulz <david.schulz@qt.io> | 2019-05-17 09:18:41 +0000 |
commit | c874f07d53ea8a0d4b2c0ead4b7671c2aec99eb2 (patch) | |
tree | e22f7d81c92b30ee992dcac2c4b1860f9a91d0d6 /src/plugins | |
parent | e04339b1e8105a570abb34c825da73c8f0df5f8b (diff) | |
download | qt-creator-c874f07d53ea8a0d4b2c0ead4b7671c2aec99eb2.tar.gz |
LanguageClient: add hover handler
Change-Id: Iddf30828ef26a157ab935d0abe708087ab123dd6
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/languageclient/client.cpp | 17 | ||||
-rw-r--r-- | src/plugins/languageclient/client.h | 3 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclient.pro | 2 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclient.qbs | 2 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclienthoverhandler.cpp | 148 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclienthoverhandler.h | 59 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclientmanager.cpp | 2 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.cpp | 5 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.h | 5 |
9 files changed, 241 insertions, 2 deletions
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 52f63cc07b..b6eecb4fdb 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -96,6 +96,7 @@ Client::Client(BaseClientInterface *clientInterface) , m_quickFixProvider(this) , m_clientInterface(clientInterface) , m_documentSymbolCache(this) + , m_hoverHandler(this) { m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(), &JsonRpcMessageHandler::parseContent); @@ -129,6 +130,7 @@ Client::~Client() if (auto textEditor = qobject_cast<BaseTextEditor *>(editor)) { TextEditorWidget *widget = textEditor->editorWidget(); widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); + widget->removeHoverHandler(&m_hoverHandler); } } for (const DocumentUri &uri : m_diagnostics.keys()) @@ -204,6 +206,12 @@ static ClientCapabilities generateClientCapabilities() CodeActionKind(QList<QString>{"*"})); codeActionCapabilities.setCodeActionLiteralSupport(literalSupport); documentCapabilities.setCodeAction(codeActionCapabilities); + + TextDocumentClientCapabilities::HoverCapabilities hover; + hover.setContentFormat({MarkupKind::plaintext}); + hover.setDynamicRegistration(true); + documentCapabilities.setHover(hover); + documentCapabilities.setReferences(allowDynamicRegistration); documentCapabilities.setDocumentHighlight(allowDynamicRegistration); documentCapabilities.setDefinition(allowDynamicRegistration); @@ -915,6 +923,11 @@ DocumentSymbolCache *Client::documentSymbolCache() return &m_documentSymbolCache; } +HoverHandler *Client::hoverHandler() +{ + return &m_hoverHandler; +} + void Client::log(const ShowMessageParams &message, Core::MessageManager::PrintToOutputPaneFlag flag) { @@ -1113,6 +1126,10 @@ void Client::intializeCallback(const InitializeRequest::Response &initResponse) updateEditorToolBar(editor); } } + for (Core::IEditor *editor : Core::DocumentModel::editorsForOpenedDocuments()) { + if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) + textEditor->editorWidget()->addHoverHandler(&m_hoverHandler); + } emit initialized(m_serverCapabilities); } diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index bd679ead93..81bb101d14 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -30,6 +30,7 @@ #include "languageclientcompletionassist.h" #include "languageclientquickfix.h" #include "languageclientsettings.h" +#include "languageclienthoverhandler.h" #include <coreplugin/id.h> #include <coreplugin/messagemanager.h> @@ -155,6 +156,7 @@ public: const DynamicCapabilities &dynamicCapabilities() const; const BaseClientInterface *clientInterface() const; DocumentSymbolCache *documentSymbolCache(); + HoverHandler *hoverHandler(); signals: void initialized(LanguageServerProtocol::ServerCapabilities capabilities); @@ -205,6 +207,7 @@ private: QScopedPointer<BaseClientInterface> m_clientInterface; QMap<LanguageServerProtocol::DocumentUri, QList<TextMark *>> m_diagnostics; DocumentSymbolCache m_documentSymbolCache; + HoverHandler m_hoverHandler; const ProjectExplorer::Project *m_project = nullptr; }; diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro index 7ff9bf3574..e3bfd5870a 100644 --- a/src/plugins/languageclient/languageclient.pro +++ b/src/plugins/languageclient/languageclient.pro @@ -8,6 +8,7 @@ HEADERS += \ dynamiccapabilities.h \ languageclient_global.h \ languageclientcompletionassist.h \ + languageclienthoverhandler.h \ languageclientinterface.h \ languageclientmanager.h \ languageclientoutline.h \ @@ -23,6 +24,7 @@ SOURCES += \ documentsymbolcache.cpp \ dynamiccapabilities.cpp \ languageclientcompletionassist.cpp \ + languageclienthoverhandler.cpp \ languageclientinterface.cpp \ languageclientmanager.cpp \ languageclientoutline.cpp \ diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index b743675c09..13cba8201b 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -22,6 +22,8 @@ QtcPlugin { "dynamiccapabilities.h", "languageclient.qrc", "languageclient_global.h", + "languageclienthoverhandler.cpp", + "languageclienthoverhandler.h", "languageclientinterface.cpp", "languageclientinterface.h", "languageclientcompletionassist.cpp", diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp new file mode 100644 index 0000000000..166fdc3049 --- /dev/null +++ b/src/plugins/languageclient/languageclienthoverhandler.cpp @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "languageclienthoverhandler.h" + +#include "client.h" + +#include <texteditor/textdocument.h> +#include <texteditor/texteditor.h> +#include <utils/mimetypes/mimedatabase.h> +#include <utils/qtcassert.h> +#include <utils/tooltip/tooltip.h> + +using namespace LanguageServerProtocol; + +namespace LanguageClient { + +HoverHandler::HoverHandler(Client *client) + : m_client(client) +{} + +HoverHandler::~HoverHandler() +{ + abort(); +} + +void HoverHandler::abort() +{ + if (m_client && m_client->reachable() && m_currentRequest.has_value()) + m_client->cancelRequest(*m_currentRequest); + m_currentRequest.reset(); +} + +void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, + int pos, + TextEditor::BaseHoverHandler::ReportPriority report) +{ + if (m_currentRequest.has_value()) + abort(); + if (m_client.isNull() + || !m_client->documentOpen(editorWidget->textDocument()) + || !m_client->capabilities().hoverProvider().value_or(false)) { + report(Priority_None); + return; + } + + bool sendMessage = m_client->capabilities().hoverProvider().value_or(false); + if (Utils::optional<bool> registered = m_client->dynamicCapabilities().isRegistered( + HoverRequest::methodName)) { + sendMessage = registered.value(); + if (sendMessage) { + const TextDocumentRegistrationOptions option( + m_client->dynamicCapabilities().option(HoverRequest::methodName).toObject()); + if (option.isValid(nullptr)) { + sendMessage = option.filterApplies(editorWidget->textDocument()->filePath(), + Utils::mimeTypeForName( + editorWidget->textDocument()->mimeType())); + } + } + } + if (!sendMessage) { + report(Priority_None); + return; + } + + m_report = report; + auto uri = DocumentUri::fromFileName(editorWidget->textDocument()->filePath()); + QTextCursor cursor = editorWidget->textCursor(); + cursor.setPosition(pos); + TextDocumentPositionParams params(uri, Position(cursor)); + HoverRequest request(params); + request.setResponseCallback( + [this](const HoverRequest::Response &response) { handleResponse(response); }); + m_client->sendContent(request); +} + +void HoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) +{ + if (toolTip().isEmpty()) + Utils::ToolTip::hide(); + else + Utils::ToolTip::show(point, toolTip(), editorWidget); +} + +void HoverHandler::handleResponse(const HoverRequest::Response &response) +{ + m_currentRequest.reset(); + if (Utils::optional<HoverRequest::Response::Error> error = response.error()) { + if (m_client) + m_client->log(error.value()); + } + if (Utils::optional<Hover> result = response.result()) + setContent(result.value().content()); + m_report(priority()); +} + +static QString toolTipForMarkedStrings(const QList<MarkedString> &markedStrings) +{ + QString tooltip; + for (const MarkedString &markedString : markedStrings) { + if (!tooltip.isEmpty()) + tooltip += '\n'; + if (auto string = Utils::get_if<QString>(&markedString)) + tooltip += *string; + else if (auto string = Utils::get_if<MarkedLanguageString>(&markedString)) + tooltip += string->value() + " [" + string->language() + ']'; + } + return tooltip; +} + +void HoverHandler::setContent(const HoverContent &hoverContent) +{ + if (auto markupContent = Utils::get_if<MarkupContent>(&hoverContent)) { + const QString &content = markupContent->content(); + if (markupContent->kind() == MarkupKind::plaintext) + setToolTip(content); + else if (m_client) + m_client->log(tr("Got unsupported markup hover content: ") + content); + } else if (auto markedString = Utils::get_if<MarkedString>(&hoverContent)) { + setToolTip(toolTipForMarkedStrings({*markedString})); + } else if (auto markedStrings = Utils::get_if<QList<MarkedString>>(&hoverContent)) { + setToolTip(toolTipForMarkedStrings(*markedStrings)); + } +} + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclienthoverhandler.h b/src/plugins/languageclient/languageclienthoverhandler.h new file mode 100644 index 0000000000..88a439e211 --- /dev/null +++ b/src/plugins/languageclient/languageclienthoverhandler.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <languageserverprotocol/languagefeatures.h> +#include <texteditor/basehoverhandler.h> + +namespace LanguageClient { + +class Client; + +class HoverHandler : public TextEditor::BaseHoverHandler +{ + Q_DECLARE_TR_FUNCTIONS(HoverHandler) +public: + explicit HoverHandler(Client *client); + ~HoverHandler() override; + + void abort() override; + +protected: + void identifyMatch(TextEditor::TextEditorWidget *editorWidget, + int pos, + ReportPriority report) override; + void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; + +private: + void handleResponse(const LanguageServerProtocol::HoverRequest::Response &response); + void setContent(const LanguageServerProtocol::HoverContent &content); + + QPointer<Client> m_client; + Utils::optional<LanguageServerProtocol::MessageId> m_currentRequest; + TextEditor::BaseHoverHandler::ReportPriority m_report; +}; + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 45b91674fe..b519c13fef 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -362,6 +362,8 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor) }); }); updateEditorToolBar(editor); + for (auto client : reachableClients()) + widget->addHoverHandler(client->hoverHandler()); } } } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 24b061fed7..97970dbd6e 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5822,6 +5822,11 @@ void TextEditorWidget::addHoverHandler(BaseHoverHandler *handler) d->m_hoverHandlers.append(handler); } +void TextEditorWidget::removeHoverHandler(BaseHoverHandler *handler) +{ + d->m_hoverHandlers.removeAll(handler); +} + void TextEditorWidget::extraAreaLeaveEvent(QEvent *) { d->extraAreaPreviousMarkTooltipRequestedLine = -1; diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 3d079bf77f..08b6738a5e 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -474,6 +474,9 @@ public: Core::HighlightScrollBarController *highlightScrollBarController() const; + void addHoverHandler(BaseHoverHandler *handler); + void removeHoverHandler(BaseHoverHandler *handler); + signals: void assistFinished(); // Used in tests. void readOnlyChanged(); @@ -534,8 +537,6 @@ protected: virtual void finalizeInitializationAfterDuplication(TextEditorWidget *) {} static QTextCursor flippedCursor(const QTextCursor &cursor); - void addHoverHandler(BaseHoverHandler *handler); - public: QString selectedText() const; |