summaryrefslogtreecommitdiff
path: root/src/plugins/languageclient
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2019-05-15 11:19:31 +0200
committerDavid Schulz <david.schulz@qt.io>2019-05-17 09:18:41 +0000
commitc874f07d53ea8a0d4b2c0ead4b7671c2aec99eb2 (patch)
treee22f7d81c92b30ee992dcac2c4b1860f9a91d0d6 /src/plugins/languageclient
parente04339b1e8105a570abb34c825da73c8f0df5f8b (diff)
downloadqt-creator-c874f07d53ea8a0d4b2c0ead4b7671c2aec99eb2.tar.gz
LanguageClient: add hover handler
Change-Id: Iddf30828ef26a157ab935d0abe708087ab123dd6 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/languageclient')
-rw-r--r--src/plugins/languageclient/client.cpp17
-rw-r--r--src/plugins/languageclient/client.h3
-rw-r--r--src/plugins/languageclient/languageclient.pro2
-rw-r--r--src/plugins/languageclient/languageclient.qbs2
-rw-r--r--src/plugins/languageclient/languageclienthoverhandler.cpp148
-rw-r--r--src/plugins/languageclient/languageclienthoverhandler.h59
-rw-r--r--src/plugins/languageclient/languageclientmanager.cpp2
7 files changed, 233 insertions, 0 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());
}
}
}