forked from qt-creator/qt-creator
LanguageClient: add cache for document symbols
Change-Id: Ia4c4061258c74d839edbd472c2087be74ac30113 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -94,6 +94,7 @@ Client::Client(BaseClientInterface *clientInterface)
|
|||||||
, m_completionProvider(this)
|
, m_completionProvider(this)
|
||||||
, m_quickFixProvider(this)
|
, m_quickFixProvider(this)
|
||||||
, m_clientInterface(clientInterface)
|
, m_clientInterface(clientInterface)
|
||||||
|
, m_documentSymbolCache(this)
|
||||||
{
|
{
|
||||||
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
|
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
|
||||||
&JsonRpcMessageHandler::parseContent);
|
&JsonRpcMessageHandler::parseContent);
|
||||||
@@ -859,6 +860,11 @@ const BaseClientInterface *Client::clientInterface() const
|
|||||||
return m_clientInterface.data();
|
return m_clientInterface.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DocumentSymbolCache *Client::documentSymbolCache()
|
||||||
|
{
|
||||||
|
return &m_documentSymbolCache;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::log(const ShowMessageParams &message,
|
void Client::log(const ShowMessageParams &message,
|
||||||
Core::MessageManager::PrintToOutputPaneFlag flag)
|
Core::MessageManager::PrintToOutputPaneFlag flag)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "documentsymbolcache.h"
|
||||||
#include "dynamiccapabilities.h"
|
#include "dynamiccapabilities.h"
|
||||||
#include "languageclientcompletionassist.h"
|
#include "languageclientcompletionassist.h"
|
||||||
#include "languageclientquickfix.h"
|
#include "languageclientquickfix.h"
|
||||||
@@ -148,6 +149,7 @@ public:
|
|||||||
const LanguageServerProtocol::ServerCapabilities &capabilities() const;
|
const LanguageServerProtocol::ServerCapabilities &capabilities() const;
|
||||||
const DynamicCapabilities &dynamicCapabilities() const;
|
const DynamicCapabilities &dynamicCapabilities() const;
|
||||||
const BaseClientInterface *clientInterface() const;
|
const BaseClientInterface *clientInterface() const;
|
||||||
|
DocumentSymbolCache *documentSymbolCache();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initialized(LanguageServerProtocol::ServerCapabilities capabilities);
|
void initialized(LanguageServerProtocol::ServerCapabilities capabilities);
|
||||||
@@ -197,6 +199,7 @@ private:
|
|||||||
int m_restartsLeft = 5;
|
int m_restartsLeft = 5;
|
||||||
QScopedPointer<BaseClientInterface> m_clientInterface;
|
QScopedPointer<BaseClientInterface> m_clientInterface;
|
||||||
QMap<LanguageServerProtocol::DocumentUri, QList<TextMark *>> m_diagnostics;
|
QMap<LanguageServerProtocol::DocumentUri, QList<TextMark *>> m_diagnostics;
|
||||||
|
DocumentSymbolCache m_documentSymbolCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
||||||
|
|||||||
81
src/plugins/languageclient/documentsymbolcache.cpp
Normal file
81
src/plugins/languageclient/documentsymbolcache.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "documentsymbolcache.h"
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <texteditor/textdocument.h>
|
||||||
|
|
||||||
|
using namespace LanguageServerProtocol;
|
||||||
|
|
||||||
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
DocumentSymbolCache::DocumentSymbolCache(Client *client)
|
||||||
|
: QObject(client)
|
||||||
|
, m_client(client)
|
||||||
|
{
|
||||||
|
connect(Core::EditorManager::instance(),
|
||||||
|
&Core::EditorManager::documentOpened,
|
||||||
|
this,
|
||||||
|
[this](Core::IDocument *document) {
|
||||||
|
connect(document, &Core::IDocument::contentsChanged, this, [this, document]() {
|
||||||
|
m_cache.remove(DocumentUri::fromFileName(document->filePath()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentSymbolCache::requestSymbols(const DocumentUri &uri)
|
||||||
|
{
|
||||||
|
auto entry = m_cache.find(uri);
|
||||||
|
if (entry != m_cache.end()) {
|
||||||
|
emit gotSymbols(uri, entry.value());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DocumentSymbolParams params((TextDocumentIdentifier(uri)));
|
||||||
|
DocumentSymbolsRequest request(params);
|
||||||
|
request.setResponseCallback([uri, self = QPointer<DocumentSymbolCache>(this)](
|
||||||
|
const DocumentSymbolsRequest::Response &response) {
|
||||||
|
if (self)
|
||||||
|
self->handleResponse(uri, response);
|
||||||
|
});
|
||||||
|
m_client->sendContent(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DocumentSymbolCache::handleResponse(const DocumentUri &uri,
|
||||||
|
const DocumentSymbolsRequest::Response &response)
|
||||||
|
{
|
||||||
|
if (Utils::optional<DocumentSymbolsRequest::Response::Error> error = response.error()) {
|
||||||
|
if (m_client)
|
||||||
|
m_client->log(error.value());
|
||||||
|
}
|
||||||
|
const DocumentSymbolsResult &symbols = response.result().value_or(DocumentSymbolsResult());
|
||||||
|
m_cache[uri] = symbols;
|
||||||
|
emit gotSymbols(uri, symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace LanguageClient
|
||||||
58
src/plugins/languageclient/documentsymbolcache.h
Normal file
58
src/plugins/languageclient/documentsymbolcache.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "utils/optional.h"
|
||||||
|
|
||||||
|
#include <languageserverprotocol/languagefeatures.h>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
class Client;
|
||||||
|
|
||||||
|
class DocumentSymbolCache : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DocumentSymbolCache(Client *client);
|
||||||
|
|
||||||
|
void requestSymbols(const LanguageServerProtocol::DocumentUri &uri);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void gotSymbols(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const LanguageServerProtocol::DocumentSymbolsResult &symbols);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleResponse(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const LanguageServerProtocol::DocumentSymbolsRequest::Response &response);
|
||||||
|
|
||||||
|
QMap<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::DocumentSymbolsResult> m_cache;
|
||||||
|
Client *m_client = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace LanguageClient
|
||||||
@@ -4,6 +4,7 @@ DEFINES += LANGUAGECLIENT_LIBRARY
|
|||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
client.h \
|
client.h \
|
||||||
|
documentsymbolcache.h \
|
||||||
dynamiccapabilities.h \
|
dynamiccapabilities.h \
|
||||||
languageclient_global.h \
|
languageclient_global.h \
|
||||||
languageclientcompletionassist.h \
|
languageclientcompletionassist.h \
|
||||||
@@ -18,6 +19,7 @@ HEADERS += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
client.cpp \
|
client.cpp \
|
||||||
|
documentsymbolcache.cpp \
|
||||||
dynamiccapabilities.cpp \
|
dynamiccapabilities.cpp \
|
||||||
languageclientcompletionassist.cpp \
|
languageclientcompletionassist.cpp \
|
||||||
languageclientinterface.cpp \
|
languageclientinterface.cpp \
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ QtcPlugin {
|
|||||||
files: [
|
files: [
|
||||||
"client.cpp",
|
"client.cpp",
|
||||||
"client.h",
|
"client.h",
|
||||||
|
"documentsymbolcache.cpp",
|
||||||
|
"documentsymbolcache.h",
|
||||||
"dynamiccapabilities.cpp",
|
"dynamiccapabilities.cpp",
|
||||||
"dynamiccapabilities.h",
|
"dynamiccapabilities.h",
|
||||||
"languageclient.qrc",
|
"languageclient.qrc",
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ public:
|
|||||||
void setCursorSynchronization(bool syncWithCursor) override;
|
void setCursorSynchronization(bool syncWithCursor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleResponse(const LanguageServerProtocol::DocumentSymbolsRequest::Response &response);
|
void handleResponse(const DocumentUri &uri, const DocumentSymbolsResult &response);
|
||||||
void updateTextCursor(const QModelIndex &proxyIndex);
|
void updateTextCursor(const QModelIndex &proxyIndex);
|
||||||
void updateSelectionInTree(const QTextCursor ¤tCursor);
|
void updateSelectionInTree(const QTextCursor ¤tCursor);
|
||||||
void onItemActivated(const QModelIndex &index);
|
void onItemActivated(const QModelIndex &index);
|
||||||
@@ -164,6 +164,7 @@ private:
|
|||||||
QPointer<TextEditor::BaseTextEditor> m_editor;
|
QPointer<TextEditor::BaseTextEditor> m_editor;
|
||||||
LanguageClientOutlineModel m_model;
|
LanguageClientOutlineModel m_model;
|
||||||
Utils::TreeView m_view;
|
Utils::TreeView m_view;
|
||||||
|
DocumentUri m_uri;
|
||||||
bool m_sync = false;
|
bool m_sync = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -172,23 +173,19 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client,
|
|||||||
: m_client(client)
|
: m_client(client)
|
||||||
, m_editor(editor)
|
, m_editor(editor)
|
||||||
, m_view(this)
|
, m_view(this)
|
||||||
|
, m_uri(DocumentUri::fromFileName(editor->textDocument()->filePath()))
|
||||||
{
|
{
|
||||||
const DocumentSymbolParams params(
|
connect(client->documentSymbolCache(),
|
||||||
TextDocumentIdentifier(
|
&DocumentSymbolCache::gotSymbols,
|
||||||
DocumentUri::fromFileName(editor->textDocument()->filePath())));
|
this,
|
||||||
DocumentSymbolsRequest request(params);
|
&LanguageClientOutlineWidget::handleResponse);
|
||||||
request.setResponseCallback([self = QPointer<LanguageClientOutlineWidget>(this)]
|
client->documentSymbolCache()->requestSymbols(m_uri);
|
||||||
(const DocumentSymbolsRequest::Response &response){
|
|
||||||
if (self)
|
|
||||||
self->handleResponse(response);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto *layout = new QVBoxLayout;
|
auto *layout = new QVBoxLayout;
|
||||||
layout->setMargin(0);
|
layout->setMargin(0);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view));
|
layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view));
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
client->sendContent(request);
|
|
||||||
m_view.setModel(&m_model);
|
m_view.setModel(&m_model);
|
||||||
m_view.setHeaderHidden(true);
|
m_view.setHeaderHidden(true);
|
||||||
connect(&m_view, &QAbstractItemView::activated,
|
connect(&m_view, &QAbstractItemView::activated,
|
||||||
@@ -212,20 +209,17 @@ void LanguageClientOutlineWidget::setCursorSynchronization(bool syncWithCursor)
|
|||||||
updateSelectionInTree(m_editor->textCursor());
|
updateSelectionInTree(m_editor->textCursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageClientOutlineWidget::handleResponse(const DocumentSymbolsRequest::Response &response)
|
void LanguageClientOutlineWidget::handleResponse(const DocumentUri &uri,
|
||||||
|
const DocumentSymbolsResult &result)
|
||||||
{
|
{
|
||||||
if (Utils::optional<DocumentSymbolsRequest::Response::Error> error = response.error()) {
|
if (uri != m_uri)
|
||||||
if (m_client)
|
return;
|
||||||
m_client->log(error.value());
|
if (Utils::holds_alternative<QList<SymbolInformation>>(result))
|
||||||
}
|
m_model.setInfo(Utils::get<QList<SymbolInformation>>(result));
|
||||||
if (Utils::optional<DocumentSymbolsResult> result = response.result()) {
|
else if (Utils::holds_alternative<QList<DocumentSymbol>>(result))
|
||||||
if (Utils::holds_alternative<QList<SymbolInformation>>(result.value()))
|
m_model.setInfo(Utils::get<QList<DocumentSymbol>>(result));
|
||||||
m_model.setInfo(Utils::get<QList<SymbolInformation>>(result.value()));
|
else
|
||||||
else if (Utils::holds_alternative<QList<DocumentSymbol>>(result.value()))
|
m_model.clear();
|
||||||
m_model.setInfo(Utils::get<QList<DocumentSymbol>>(result.value()));
|
|
||||||
else
|
|
||||||
m_model.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageClientOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex)
|
void LanguageClientOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex)
|
||||||
|
|||||||
Reference in New Issue
Block a user