diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index 239d40f6622..4adc35aa105 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -556,7 +556,6 @@ enum class SymbolKind { TypeParameter = 26, LastSymbolKind = TypeParameter, }; -using SymbolStringifier = std::function; namespace CompletionItemKind { enum Kind { diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 2c3f722617b..fb097b5aac2 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,20 @@ public: : 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(type()), name(), detail()); + } + return LanguageClientOutlineItem::data(column, role); + } +}; + void setupClangdConfigFile() { const Utils::FilePath targetConfigFile = CppEditor::ClangdSettings::clangdUserConfigFilePath(); @@ -427,7 +442,6 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c }); setCurrentProject(project); setDocumentChangeUpdateThreshold(d->settings.documentUpdateThreshold); - setSymbolStringifier(displayNameFromDocumentSymbol); setSemanticTokensHandler([this](TextDocument *doc, const QList &tokens, int version, bool force) { d->handleSemanticTokens(doc, tokens, version, force); @@ -661,6 +675,12 @@ DiagnosticManager *ClangdClient::createDiagnosticManager() return diagnosticManager; } +LanguageClientOutlineItem *ClangdClient::createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol) +{ + return new ClangdOutlineItem(this, symbol); +} + bool ClangdClient::referencesShadowFile(const TextEditor::TextDocument *doc, const Utils::FilePath &candidate) { diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 772920b2776..3c9e603b843 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -137,6 +137,8 @@ private: const CustomInspectorTabs createCustomInspectorTabs() override; TextEditor::RefactoringChangesData *createRefactoringChangesBackend() const override; LanguageClient::DiagnosticManager *createDiagnosticManager() override; + LanguageClient::LanguageClientOutlineItem *createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol) override; bool referencesShadowFile(const TextEditor::TextDocument *doc, const Utils::FilePath &candidate) override; bool fileBelongsToProject(const Utils::FilePath &filePath) const override; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 0efaacd3500..23c086c8b2e 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -11,6 +11,7 @@ #include "languageclienthoverhandler.h" #include "languageclientinterface.h" #include "languageclientmanager.h" +#include "languageclientoutline.h" #include "languageclientquickfix.h" #include "languageclientsymbolsupport.h" #include "languageclientutils.h" @@ -325,7 +326,6 @@ public: SemanticTokenSupport m_tokenSupport; QString m_serverName; QString m_serverVersion; - LanguageServerProtocol::SymbolStringifier m_symbolStringifier; Client::LogTarget m_logTarget = Client::LogTarget::Ui; bool m_locatorsEnabled = true; bool m_autoRequestCodeActions = true; @@ -1484,16 +1484,6 @@ void Client::setSemanticTokensHandler(const SemanticTokensHandler &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) { if (const auto provider = qobject_cast( @@ -2089,6 +2079,12 @@ bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const 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) { const FilePath onDevice = serverDeviceTemplate.withNewPath(localClientPath.path()); diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 525739d7a63..51f72cc7d4a 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -31,7 +31,6 @@ class Unregistration; } // namespace LanguageServerProtocol namespace LanguageClient { - class BaseClientInterface; class ClientPrivate; class DiagnosticManager; @@ -40,6 +39,7 @@ class DynamicCapabilities; class HoverHandler; class InterfaceController; class LanguageClientCompletionAssistProvider; +class LanguageClientOutlineItem; class LanguageClientQuickFixProvider; class LanguageFilter; class ProgressManager; @@ -160,13 +160,13 @@ public: const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const; void setSemanticTokensHandler(const SemanticTokensHandler &handler); - void setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier); - LanguageServerProtocol::SymbolStringifier symbolStringifier() const; void setSnippetsGroup(const QString &group); void setCompletionAssistProvider(LanguageClientCompletionAssistProvider *provider); void setQuickFixAssistProvider(LanguageClientQuickFixProvider *provider); virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const; + virtual LanguageClientOutlineItem *createOutlineItem( + const LanguageServerProtocol::DocumentSymbol &symbol); LanguageServerProtocol::DocumentUri::PathMapper hostPathMapper() const; Utils::FilePath serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const; diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 9ab057de62f..6d0596780ea 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -41,67 +41,10 @@ const QList sortedSymbols(const QList &symbols) }); } -class LanguageClientOutlineItem : public Utils::TypedTreeItem -{ -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 children = sortedSymbols( - info.children().value_or(QList())); - 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(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::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 { public: - using Utils::TreeModel::TreeModel; + LanguageClientOutlineModel(Client *client) : m_client(client) {} void setFilePath(const Utils::FilePath &filePath) { m_filePath = filePath; } void setInfo(const QList &info) @@ -114,12 +57,7 @@ public: { clear(); for (const DocumentSymbol &symbol : sortedSymbols(info)) - rootItem()->appendChild(new LanguageClientOutlineItem(symbol, m_symbolStringifier)); - } - - void setSymbolStringifier(const SymbolStringifier &stringifier) - { - m_symbolStringifier = stringifier; + rootItem()->appendChild(m_client->createOutlineItem(symbol)); } Qt::DropActions supportedDragActions() const override @@ -145,7 +83,7 @@ public: } private: - SymbolStringifier m_symbolStringifier; + Client * const m_client; Utils::FilePath m_filePath; }; @@ -194,6 +132,7 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, TextEditor::BaseTextEditor *editor) : m_client(client) , m_editor(editor) + , m_model(client) , m_view(this) , m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath())) { @@ -213,7 +152,6 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, layout->setSpacing(0); layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view)); setLayout(layout); - m_model.setSymbolStringifier(m_client->symbolStringifier()); m_model.setFilePath(editor->textDocument()->filePath()); m_proxyModel.setSourceModel(&m_model); m_view.setModel(&m_proxyModel); @@ -372,11 +310,11 @@ Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox( } OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) - : m_client(client) + : m_model(client) + , m_client(client) , m_editorWidget(editor->editorWidget()) , m_uri(m_client->hostPathToServerUri(editor->document()->filePath())) { - m_model.setSymbolStringifier(client->symbolStringifier()); m_proxyModel.setSourceModel(&m_model); const bool sorted = LanguageClientSettings::outlineComboBoxIsSorted(); m_proxyModel.sort(sorted ? 0 : -1); @@ -455,4 +393,39 @@ void OutlineComboBox::setSorted(bool sorted) 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 children = sortedSymbols( + info.children().value_or(QList())); + 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::flags(column) | Qt::ItemIsDragEnabled; +} } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientoutline.h b/src/plugins/languageclient/languageclientoutline.h index e333563dc2d..1dc73dd4c9a 100644 --- a/src/plugins/languageclient/languageclientoutline.h +++ b/src/plugins/languageclient/languageclientoutline.h @@ -3,7 +3,11 @@ #pragma once +#include "languageclient_global.h" + +#include #include +#include namespace TextEditor { class TextDocument; @@ -12,6 +16,38 @@ class BaseTextEditor; namespace Utils { class TreeViewComboBox; } namespace LanguageClient { +class Client; + +class LANGUAGECLIENT_EXPORT LanguageClientOutlineItem + : public Utils::TypedTreeItem +{ +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;