LanguageClient: Export LanguageClientOutlineItem

To enable more customizations by specialized clients.

Change-Id: I0ad92e248e931389c3fa239df424df8883e1d86e
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2023-02-03 14:46:00 +01:00
parent dc5d416937
commit cc52478a93
7 changed files with 110 additions and 84 deletions

View File

@@ -556,7 +556,6 @@ enum class SymbolKind {
TypeParameter = 26, TypeParameter = 26,
LastSymbolKind = TypeParameter, LastSymbolKind = TypeParameter,
}; };
using SymbolStringifier = std::function<QString(SymbolKind, const QString &, const QString &)>;
namespace CompletionItemKind { namespace CompletionItemKind {
enum Kind { enum Kind {

View File

@@ -38,6 +38,7 @@
#include <languageclient/languageclienthoverhandler.h> #include <languageclient/languageclienthoverhandler.h>
#include <languageclient/languageclientinterface.h> #include <languageclient/languageclientinterface.h>
#include <languageclient/languageclientmanager.h> #include <languageclient/languageclientmanager.h>
#include <languageclient/languageclientoutline.h>
#include <languageclient/languageclientsymbolsupport.h> #include <languageclient/languageclientsymbolsupport.h>
#include <languageclient/languageclientutils.h> #include <languageclient/languageclientutils.h>
#include <languageclient/progressmanager.h> #include <languageclient/progressmanager.h>
@@ -128,6 +129,20 @@ public:
: Request("textDocument/symbolInfo", params) {} : Request("textDocument/symbolInfo", params) {}
}; };
class ClangdOutlineItem : public LanguageClientOutlineItem
{
using LanguageClientOutlineItem::LanguageClientOutlineItem;
private:
QVariant data(int column, int role) const override
{
if (role == Qt::DisplayRole) {
return ClangdClient::displayNameFromDocumentSymbol(
static_cast<SymbolKind>(type()), name(), detail());
}
return LanguageClientOutlineItem::data(column, role);
}
};
void setupClangdConfigFile() void setupClangdConfigFile()
{ {
const Utils::FilePath targetConfigFile = CppEditor::ClangdSettings::clangdUserConfigFilePath(); const Utils::FilePath targetConfigFile = CppEditor::ClangdSettings::clangdUserConfigFilePath();
@@ -427,7 +442,6 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c
}); });
setCurrentProject(project); setCurrentProject(project);
setDocumentChangeUpdateThreshold(d->settings.documentUpdateThreshold); setDocumentChangeUpdateThreshold(d->settings.documentUpdateThreshold);
setSymbolStringifier(displayNameFromDocumentSymbol);
setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens, setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens,
int version, bool force) { int version, bool force) {
d->handleSemanticTokens(doc, tokens, version, force); d->handleSemanticTokens(doc, tokens, version, force);
@@ -661,6 +675,12 @@ DiagnosticManager *ClangdClient::createDiagnosticManager()
return diagnosticManager; return diagnosticManager;
} }
LanguageClientOutlineItem *ClangdClient::createOutlineItem(
const LanguageServerProtocol::DocumentSymbol &symbol)
{
return new ClangdOutlineItem(this, symbol);
}
bool ClangdClient::referencesShadowFile(const TextEditor::TextDocument *doc, bool ClangdClient::referencesShadowFile(const TextEditor::TextDocument *doc,
const Utils::FilePath &candidate) const Utils::FilePath &candidate)
{ {

View File

@@ -137,6 +137,8 @@ private:
const CustomInspectorTabs createCustomInspectorTabs() override; const CustomInspectorTabs createCustomInspectorTabs() override;
TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override; TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override;
LanguageClient::DiagnosticManager *createDiagnosticManager() override; LanguageClient::DiagnosticManager *createDiagnosticManager() override;
LanguageClient::LanguageClientOutlineItem *createOutlineItem(
const LanguageServerProtocol::DocumentSymbol &symbol) override;
bool referencesShadowFile(const TextEditor::TextDocument *doc, bool referencesShadowFile(const TextEditor::TextDocument *doc,
const Utils::FilePath &candidate) override; const Utils::FilePath &candidate) override;
bool fileBelongsToProject(const Utils::FilePath &filePath) const override; bool fileBelongsToProject(const Utils::FilePath &filePath) const override;

View File

@@ -11,6 +11,7 @@
#include "languageclienthoverhandler.h" #include "languageclienthoverhandler.h"
#include "languageclientinterface.h" #include "languageclientinterface.h"
#include "languageclientmanager.h" #include "languageclientmanager.h"
#include "languageclientoutline.h"
#include "languageclientquickfix.h" #include "languageclientquickfix.h"
#include "languageclientsymbolsupport.h" #include "languageclientsymbolsupport.h"
#include "languageclientutils.h" #include "languageclientutils.h"
@@ -325,7 +326,6 @@ public:
SemanticTokenSupport m_tokenSupport; SemanticTokenSupport m_tokenSupport;
QString m_serverName; QString m_serverName;
QString m_serverVersion; QString m_serverVersion;
LanguageServerProtocol::SymbolStringifier m_symbolStringifier;
Client::LogTarget m_logTarget = Client::LogTarget::Ui; Client::LogTarget m_logTarget = Client::LogTarget::Ui;
bool m_locatorsEnabled = true; bool m_locatorsEnabled = true;
bool m_autoRequestCodeActions = true; bool m_autoRequestCodeActions = true;
@@ -1484,16 +1484,6 @@ void Client::setSemanticTokensHandler(const SemanticTokensHandler &handler)
d->m_tokenSupport.setTokensHandler(handler); d->m_tokenSupport.setTokensHandler(handler);
} }
void Client::setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier)
{
d->m_symbolStringifier = stringifier;
}
SymbolStringifier Client::symbolStringifier() const
{
return d->m_symbolStringifier;
}
void Client::setSnippetsGroup(const QString &group) void Client::setSnippetsGroup(const QString &group)
{ {
if (const auto provider = qobject_cast<LanguageClientCompletionAssistProvider *>( if (const auto provider = qobject_cast<LanguageClientCompletionAssistProvider *>(
@@ -2089,6 +2079,12 @@ bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const
return project() && project()->isKnownFile(filePath); return project() && project()->isKnownFile(filePath);
} }
LanguageClientOutlineItem *Client::createOutlineItem(
const LanguageServerProtocol::DocumentSymbol &symbol)
{
return new LanguageClientOutlineItem(this, symbol);
}
FilePath toHostPath(const FilePath serverDeviceTemplate, const FilePath localClientPath) FilePath toHostPath(const FilePath serverDeviceTemplate, const FilePath localClientPath)
{ {
const FilePath onDevice = serverDeviceTemplate.withNewPath(localClientPath.path()); const FilePath onDevice = serverDeviceTemplate.withNewPath(localClientPath.path());

View File

@@ -31,7 +31,6 @@ class Unregistration;
} // namespace LanguageServerProtocol } // namespace LanguageServerProtocol
namespace LanguageClient { namespace LanguageClient {
class BaseClientInterface; class BaseClientInterface;
class ClientPrivate; class ClientPrivate;
class DiagnosticManager; class DiagnosticManager;
@@ -40,6 +39,7 @@ class DynamicCapabilities;
class HoverHandler; class HoverHandler;
class InterfaceController; class InterfaceController;
class LanguageClientCompletionAssistProvider; class LanguageClientCompletionAssistProvider;
class LanguageClientOutlineItem;
class LanguageClientQuickFixProvider; class LanguageClientQuickFixProvider;
class LanguageFilter; class LanguageFilter;
class ProgressManager; class ProgressManager;
@@ -160,13 +160,13 @@ public:
const LanguageServerProtocol::Diagnostic &diag) const; const LanguageServerProtocol::Diagnostic &diag) const;
bool hasDiagnostics(const TextEditor::TextDocument *document) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const;
void setSemanticTokensHandler(const SemanticTokensHandler &handler); void setSemanticTokensHandler(const SemanticTokensHandler &handler);
void setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier);
LanguageServerProtocol::SymbolStringifier symbolStringifier() const;
void setSnippetsGroup(const QString &group); void setSnippetsGroup(const QString &group);
void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider);
void setQuickFixAssistProvider(LanguageClientQuickFixProvider *provider); void setQuickFixAssistProvider(LanguageClientQuickFixProvider *provider);
virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const;
virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const; virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const;
virtual LanguageClientOutlineItem *createOutlineItem(
const LanguageServerProtocol::DocumentSymbol &symbol);
LanguageServerProtocol::DocumentUri::PathMapper hostPathMapper() const; LanguageServerProtocol::DocumentUri::PathMapper hostPathMapper() const;
Utils::FilePath serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const; Utils::FilePath serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const;

View File

@@ -41,67 +41,10 @@ const QList<DocumentSymbol> sortedSymbols(const QList<DocumentSymbol> &symbols)
}); });
} }
class LanguageClientOutlineItem : public Utils::TypedTreeItem<LanguageClientOutlineItem>
{
public:
LanguageClientOutlineItem() = default;
LanguageClientOutlineItem(const SymbolInformation &info)
: m_name(info.name())
, m_range(info.location().range())
, m_type(info.kind())
{ }
LanguageClientOutlineItem(const DocumentSymbol &info, const SymbolStringifier &stringifier)
: m_name(info.name())
, m_detail(info.detail().value_or(QString()))
, m_range(info.range())
, m_symbolStringifier(stringifier)
, m_type(info.kind())
{
const QList<LanguageServerProtocol::DocumentSymbol> children = sortedSymbols(
info.children().value_or(QList<DocumentSymbol>()));
for (const DocumentSymbol &child : children)
appendChild(new LanguageClientOutlineItem(child, stringifier));
}
// TreeItem interface
QVariant data(int column, int role) const override
{
switch (role) {
case Qt::DecorationRole:
return symbolIcon(m_type);
case Qt::DisplayRole:
return m_symbolStringifier
? m_symbolStringifier(static_cast<SymbolKind>(m_type), m_name, m_detail)
: m_name;
default:
return Utils::TreeItem::data(column, role);
}
}
Qt::ItemFlags flags(int column) const override
{
Q_UNUSED(column)
return Utils::TypedTreeItem<LanguageClientOutlineItem>::flags(column)
| Qt::ItemIsDragEnabled;
}
Range range() const { return m_range; }
Position pos() const { return m_range.start(); }
bool contains(const Position &pos) const { return m_range.contains(pos); }
private:
QString m_name;
QString m_detail;
Range m_range;
SymbolStringifier m_symbolStringifier;
int m_type = -1;
};
class LanguageClientOutlineModel : public Utils::TreeModel<LanguageClientOutlineItem> class LanguageClientOutlineModel : public Utils::TreeModel<LanguageClientOutlineItem>
{ {
public: public:
using Utils::TreeModel<LanguageClientOutlineItem>::TreeModel; LanguageClientOutlineModel(Client *client) : m_client(client) {}
void setFilePath(const Utils::FilePath &filePath) { m_filePath = filePath; } void setFilePath(const Utils::FilePath &filePath) { m_filePath = filePath; }
void setInfo(const QList<SymbolInformation> &info) void setInfo(const QList<SymbolInformation> &info)
@@ -114,12 +57,7 @@ public:
{ {
clear(); clear();
for (const DocumentSymbol &symbol : sortedSymbols(info)) for (const DocumentSymbol &symbol : sortedSymbols(info))
rootItem()->appendChild(new LanguageClientOutlineItem(symbol, m_symbolStringifier)); rootItem()->appendChild(m_client->createOutlineItem(symbol));
}
void setSymbolStringifier(const SymbolStringifier &stringifier)
{
m_symbolStringifier = stringifier;
} }
Qt::DropActions supportedDragActions() const override Qt::DropActions supportedDragActions() const override
@@ -145,7 +83,7 @@ public:
} }
private: private:
SymbolStringifier m_symbolStringifier; Client * const m_client;
Utils::FilePath m_filePath; Utils::FilePath m_filePath;
}; };
@@ -194,6 +132,7 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client,
TextEditor::BaseTextEditor *editor) TextEditor::BaseTextEditor *editor)
: m_client(client) : m_client(client)
, m_editor(editor) , m_editor(editor)
, m_model(client)
, m_view(this) , m_view(this)
, m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath())) , m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath()))
{ {
@@ -213,7 +152,6 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client,
layout->setSpacing(0); layout->setSpacing(0);
layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view)); layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view));
setLayout(layout); setLayout(layout);
m_model.setSymbolStringifier(m_client->symbolStringifier());
m_model.setFilePath(editor->textDocument()->filePath()); m_model.setFilePath(editor->textDocument()->filePath());
m_proxyModel.setSourceModel(&m_model); m_proxyModel.setSourceModel(&m_model);
m_view.setModel(&m_proxyModel); m_view.setModel(&m_proxyModel);
@@ -372,11 +310,11 @@ Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox(
} }
OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor)
: m_client(client) : m_model(client)
, m_client(client)
, m_editorWidget(editor->editorWidget()) , m_editorWidget(editor->editorWidget())
, m_uri(m_client->hostPathToServerUri(editor->document()->filePath())) , m_uri(m_client->hostPathToServerUri(editor->document()->filePath()))
{ {
m_model.setSymbolStringifier(client->symbolStringifier());
m_proxyModel.setSourceModel(&m_model); m_proxyModel.setSourceModel(&m_model);
const bool sorted = LanguageClientSettings::outlineComboBoxIsSorted(); const bool sorted = LanguageClientSettings::outlineComboBoxIsSorted();
m_proxyModel.sort(sorted ? 0 : -1); m_proxyModel.sort(sorted ? 0 : -1);
@@ -455,4 +393,39 @@ void OutlineComboBox::setSorted(bool sorted)
m_proxyModel.sort(sorted ? 0 : -1); m_proxyModel.sort(sorted ? 0 : -1);
} }
LanguageClientOutlineItem::LanguageClientOutlineItem(const SymbolInformation &info)
: m_name(info.name())
, m_range(info.location().range())
, m_type(info.kind())
{ }
LanguageClientOutlineItem::LanguageClientOutlineItem(Client *client, const DocumentSymbol &info)
: m_client(client)
, m_name(info.name())
, m_detail(info.detail().value_or(QString()))
, m_range(info.range())
, m_type(info.kind())
{
const QList<LanguageServerProtocol::DocumentSymbol> children = sortedSymbols(
info.children().value_or(QList<DocumentSymbol>()));
for (const DocumentSymbol &child : children)
appendChild(m_client->createOutlineItem(child));
}
QVariant LanguageClientOutlineItem::data(int column, int role) const
{
switch (role) {
case Qt::DecorationRole:
return symbolIcon(m_type);
case Qt::DisplayRole:
return m_name;
default:
return Utils::TreeItem::data(column, role);
}
}
Qt::ItemFlags LanguageClientOutlineItem::flags(int column) const
{
Q_UNUSED(column)
return Utils::TypedTreeItem<LanguageClientOutlineItem>::flags(column) | Qt::ItemIsDragEnabled;
}
} // namespace LanguageClient } // namespace LanguageClient

View File

@@ -3,7 +3,11 @@
#pragma once #pragma once
#include "languageclient_global.h"
#include <languageserverprotocol/lsptypes.h>
#include <texteditor/ioutlinewidget.h> #include <texteditor/ioutlinewidget.h>
#include <utils/treemodel.h>
namespace TextEditor { namespace TextEditor {
class TextDocument; class TextDocument;
@@ -12,6 +16,38 @@ class BaseTextEditor;
namespace Utils { class TreeViewComboBox; } namespace Utils { class TreeViewComboBox; }
namespace LanguageClient { namespace LanguageClient {
class Client;
class LANGUAGECLIENT_EXPORT LanguageClientOutlineItem
: public Utils::TypedTreeItem<LanguageClientOutlineItem>
{
public:
LanguageClientOutlineItem() = default;
LanguageClientOutlineItem(const LanguageServerProtocol::SymbolInformation &info);
LanguageClientOutlineItem(Client *client, const LanguageServerProtocol::DocumentSymbol &info);
LanguageServerProtocol::Range range() const { return m_range; }
LanguageServerProtocol::Position pos() const { return m_range.start(); }
bool contains(const LanguageServerProtocol::Position &pos) const {
return m_range.contains(pos);
}
protected:
// TreeItem interface
QVariant data(int column, int role) const override;
Qt::ItemFlags flags(int column) const override;
QString name() const { return m_name; }
QString detail() const { return m_detail; }
int type() const { return m_type; }
private:
Client * const m_client = nullptr;
QString m_name;
QString m_detail;
LanguageServerProtocol::Range m_range;
int m_type = -1;
};
class Client; class Client;