diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 66c7bfdd814..ddcd59bd568 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -597,11 +597,13 @@ void Client::registerCapabilities(const QList ®istrations) for (auto document : m_openedDocument.keys()) updateFunctionHintProvider(document); } + emit capabilitiesChanged(m_dynamicCapabilities); } void Client::unregisterCapabilities(const QList &unregistrations) { m_dynamicCapabilities.unregisterCapability(unregistrations); + emit capabilitiesChanged(m_dynamicCapabilities); } TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation &info) @@ -1079,7 +1081,7 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon } else if (method == UnregisterCapabilityRequest::methodName) { auto params = dynamic_cast(content)->params().value_or(UnregistrationParams()); if (params.isValid(&error)) - m_dynamicCapabilities.unregisterCapability(params.unregistrations()); + unregisterCapabilities(params.unregistrations()); else logError(params); } else if (method == ApplyWorkspaceEditRequest::methodName) { diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 72894536790..5e8b2b32089 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -170,7 +170,8 @@ public: bool documentUpdatePostponed(const Utils::FilePath &fileName) const; signals: - void initialized(LanguageServerProtocol::ServerCapabilities capabilities); + void initialized(const LanguageServerProtocol::ServerCapabilities &capabilities); + void capabilitiesChanged(const DynamicCapabilities &capabilities); void documentUpdated(TextEditor::TextDocument *document); void finished(); diff --git a/src/plugins/languageclient/dynamiccapabilities.cpp b/src/plugins/languageclient/dynamiccapabilities.cpp index 1b0aef037f1..53c6c64e51f 100644 --- a/src/plugins/languageclient/dynamiccapabilities.cpp +++ b/src/plugins/languageclient/dynamiccapabilities.cpp @@ -56,6 +56,11 @@ Utils::optional DynamicCapabilities::isRegistered(const QString &method) c return m_capability[method].enabled(); } +QStringList DynamicCapabilities::registeredMethods() const +{ + return m_capability.keys(); +} + void DynamicCapabilities::reset() { m_capability.clear(); diff --git a/src/plugins/languageclient/dynamiccapabilities.h b/src/plugins/languageclient/dynamiccapabilities.h index 9abee3eac9e..18240f8b982 100644 --- a/src/plugins/languageclient/dynamiccapabilities.h +++ b/src/plugins/languageclient/dynamiccapabilities.h @@ -68,7 +68,8 @@ public: void unregisterCapability(const QList &unregistrations); Utils::optional isRegistered(const QString &method) const; - QJsonValue option(const QString &method) const { return m_capability[method].options(); } + QJsonValue option(const QString &method) const { return m_capability.value(method).options(); } + QStringList registeredMethods() const; void reset(); diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index fef29a2402e..0892fbf6455 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -108,13 +108,20 @@ void LanguageClientManager::clientStarted(Client *client) } if (!managerInstance->m_clients.contains(client)) { managerInstance->m_clients << client; - connect(client, &Client::finished, managerInstance, [client](){ - clientFinished(client); - }); + connect(client, &Client::finished, managerInstance, [client]() { clientFinished(client); }); connect(client, &Client::initialized, - &managerInstance->m_currentDocumentLocatorFilter, - &DocumentLocatorFilter::updateCurrentClient); + managerInstance, + [client](const LanguageServerProtocol::ServerCapabilities &capabilities) { + managerInstance->m_currentDocumentLocatorFilter.updateCurrentClient(); + managerInstance->m_inspector.clientInitialized(client->name(), capabilities); + }); + connect(client, + &Client::capabilitiesChanged, + managerInstance, + [client](const DynamicCapabilities &capabilities) { + managerInstance->m_inspector.updateCapabilities(client->name(), capabilities); + }); } client->initialize(); diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 4dd37cfb2e8..c5b6fd557ae 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -740,24 +740,6 @@ public: } }; -static QWidget *createCapabilitiesView(const QJsonValue &capabilities) -{ - auto root = new Utils::JsonTreeItem("Capabilities", capabilities); - if (root->canFetchMore()) - root->fetchMore(); - - auto capabilitiesModel = new Utils::TreeModel(root); - capabilitiesModel->setHeader({BaseSettingsWidget::tr("Name"), - BaseSettingsWidget::tr("Value"), - BaseSettingsWidget::tr("Type")}); - auto capabilitiesView = new QTreeView(); - capabilitiesView->setModel(capabilitiesModel); - capabilitiesView->setAlternatingRowColors(true); - capabilitiesView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - capabilitiesView->setItemDelegate(new JsonTreeItemDelegate); - return capabilitiesView; -} - static QString startupBehaviorString(BaseSettings::StartBehavior behavior) { switch (behavior) { @@ -810,32 +792,6 @@ BaseSettingsWidget::BaseSettingsWidget(const BaseSettings *settings, QWidget *pa connect(addMimeTypeButton, &QPushButton::pressed, this, &BaseSettingsWidget::showAddMimeTypeDialog); - auto createInfoLabel = []() { - return new QLabel(tr("Available after server was initialized")); - }; - - mainLayout->addWidget(new QLabel(tr("Capabilities:")), ++row, 0, Qt::AlignTop); - QVector clients = LanguageClientManager::clientForSetting(settings); - if (clients.isEmpty()) { - mainLayout->addWidget(createInfoLabel()); - } else { // TODO move the capabilities view into a new widget outside of the settings - Client *client = clients.first(); - if (client->state() == Client::Initialized) - mainLayout->addWidget(createCapabilitiesView(QJsonValue(client->capabilities()))); - else - mainLayout->addWidget(createInfoLabel(), row, 1); - connect(client, &Client::finished, mainLayout, [mainLayout, row, createInfoLabel]() { - delete mainLayout->itemAtPosition(row, 1)->widget(); - mainLayout->addWidget(createInfoLabel(), row, 1); - }); - connect(client, &Client::initialized, mainLayout, - [mainLayout, row]( - const LanguageServerProtocol::ServerCapabilities &capabilities) { - delete mainLayout->itemAtPosition(row, 1)->widget(); - mainLayout->addWidget(createCapabilitiesView(QJsonValue(capabilities)), row, 1); - }); - } - mainLayout->addWidget(new QLabel(tr("Initialization options:")), ++row, 0); mainLayout->addWidget(m_initializationOptions, row, 1); chooser->addSupportedWidget(m_initializationOptions); diff --git a/src/plugins/languageclient/lspinspector.cpp b/src/plugins/languageclient/lspinspector.cpp index 624d0572168..b8ae2938a16 100644 --- a/src/plugins/languageclient/lspinspector.cpp +++ b/src/plugins/languageclient/lspinspector.cpp @@ -51,6 +51,61 @@ using namespace LanguageServerProtocol; namespace LanguageClient { +class JsonTreeItemDelegate : public QStyledItemDelegate +{ +public: + QString displayText(const QVariant &value, const QLocale &) const override + { + QString result = value.toString(); + if (result.size() == 1) { + switch (result.at(0).toLatin1()) { + case '\n': + return QString("\\n"); + case '\t': + return QString("\\t"); + case '\r': + return QString("\\r"); + } + } + return result; + } +}; + +using JsonModel = Utils::TreeModel; + +JsonModel *createJsonModel(const QString &displayName, const QJsonValue &value) +{ + if (value.isNull()) + return nullptr; + auto root = new Utils::JsonTreeItem(displayName, value); + if (root->canFetchMore()) + root->fetchMore(); + + auto model = new JsonModel(root); + model->setHeader({{"Name"}, {"Value"}, {"Type"}}); + return model; +} + +QTreeView *createJsonTreeView() +{ + auto view = new QTreeView; + view->setContextMenuPolicy(Qt::ActionsContextMenu); + auto action = new QAction(LspInspector::tr("Expand All"), view); + QObject::connect(action, &QAction::triggered, view, &QTreeView::expandAll); + view->addAction(action); + view->setAlternatingRowColors(true); + view->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + view->setItemDelegate(new JsonTreeItemDelegate); + return view; +} + +QTreeView *createJsonTreeView(const QString &displayName, const QJsonValue &value) +{ + auto view = createJsonTreeView(); + view->setModel(createJsonModel(displayName, value)); + return view; +} + class MessageDetailWidget : public QGroupBox { public: @@ -64,53 +119,96 @@ private: QLabel *m_mimeType = nullptr; }; -class LspInspectorWidget : public QDialog +class LspCapabilitiesWidget : public QWidget { - Q_DECLARE_TR_FUNCTIONS(LspInspectorWidget) + Q_DECLARE_TR_FUNCTIONS(LspCapabilitiesWidget) public: - explicit LspInspectorWidget(LspInspector *inspector); + LspCapabilitiesWidget(); + void setCapabilities(const Capabilities &serverCapabilities); private: - void addMessage(const QString &clientName, const LspLogMessage &message); - void setCurrentClient(const QString &clientName); - void currentMessageChanged(const QModelIndex &index); - void selectMatchingMessage(LspLogMessage::MessageSender sender, const QJsonValue &id); + void updateOptionsView(const QString &method); + + DynamicCapabilities m_dynamicCapabilities; + QTreeView *m_capabilitiesView = nullptr; + QListWidget *m_dynamicCapabilitiesView = nullptr; + QTreeView *m_dynamicOptionsView = nullptr; + QGroupBox *m_dynamicCapabilitiesGroup = nullptr; +}; + +LspCapabilitiesWidget::LspCapabilitiesWidget() +{ + auto mainLayout = new QHBoxLayout; + + auto group = new QGroupBox(tr("Capabilities:")); + QLayout *layout = new QHBoxLayout; + m_capabilitiesView = createJsonTreeView(); + layout->addWidget(m_capabilitiesView); + group->setLayout(layout); + mainLayout->addWidget(group); + + m_dynamicCapabilitiesGroup = new QGroupBox(tr("Dynamic Capabilities:")); + layout = new QVBoxLayout; + auto label = new QLabel(tr("Method:")); + layout->addWidget(label); + m_dynamicCapabilitiesView = new QListWidget(); + layout->addWidget(m_dynamicCapabilitiesView); + label = new QLabel(tr("Options:")); + layout->addWidget(label); + m_dynamicOptionsView = createJsonTreeView(); + layout->addWidget(m_dynamicOptionsView); + m_dynamicCapabilitiesGroup->setLayout(layout); + mainLayout->addWidget(m_dynamicCapabilitiesGroup); + + setLayout(mainLayout); + + connect(m_dynamicCapabilitiesView, + &QListWidget::currentTextChanged, + this, + &LspCapabilitiesWidget::updateOptionsView); +} + +void LspCapabilitiesWidget::setCapabilities(const Capabilities &serverCapabilities) +{ + m_capabilitiesView->setModel( + createJsonModel(tr("Server Capabilities"), QJsonObject(serverCapabilities.capabilities))); + m_dynamicCapabilities = serverCapabilities.dynamicCapabilities; + const QStringList &methods = m_dynamicCapabilities.registeredMethods(); + if (methods.isEmpty()) { + m_dynamicCapabilitiesGroup->hide(); + return; + } + m_dynamicCapabilitiesGroup->show(); + m_dynamicCapabilitiesView->clear(); + m_dynamicCapabilitiesView->addItems(methods); +} + +void LspCapabilitiesWidget::updateOptionsView(const QString &method) +{ + QAbstractItemModel *oldModel = m_dynamicOptionsView->model(); + m_dynamicOptionsView->setModel(createJsonModel(method, m_dynamicCapabilities.option(method))); + delete oldModel; +} + +class LspLogWidget : public Core::MiniSplitter +{ +public: + LspLogWidget(); + + void addMessage(const LspLogMessage &message); + void setMessages(const std::list &messages); void saveLog(); - LspInspector *m_inspector = nullptr; - QListWidget *m_clients = nullptr; MessageDetailWidget *m_clientDetails = nullptr; QListView *m_messages = nullptr; MessageDetailWidget *m_serverDetails = nullptr; Utils::ListModel m_model; + +private: + void currentMessageChanged(const QModelIndex &index); + void selectMatchingMessage(LspLogMessage::MessageSender sender, const QJsonValue &id); }; -QWidget *LspInspector::createWidget() -{ - return new LspInspectorWidget(this); -} - -void LspInspector::log(const LspLogMessage::MessageSender sender, - const QString &clientName, - const BaseMessage &message) -{ - std::list &clientLog = m_logs[clientName]; - while (clientLog.size() >= static_cast(m_logSize)) - clientLog.pop_front(); - clientLog.push_back({sender, QTime::currentTime(), message}); - emit newMessage(clientName, clientLog.back()); -} - -std::list LspInspector::messages(const QString &clientName) const -{ - return m_logs[clientName]; -} - -QList LspInspector::clients() const -{ - return m_logs.keys(); -} - static QVariant messageData(const LspLogMessage &message, int, int role) { if (role == Qt::DisplayRole) { @@ -131,84 +229,39 @@ static QVariant messageData(const LspLogMessage &message, int, int role) return {}; } -LspInspectorWidget::LspInspectorWidget(LspInspector *inspector) - : m_inspector(inspector) +LspLogWidget::LspLogWidget() { - setWindowTitle(tr("Language Client Inspector")); - - connect(inspector, &LspInspector::newMessage, this, &LspInspectorWidget::addMessage); - connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close); - - m_clients = new QListWidget; - m_clients->addItems(inspector->clients()); - connect(m_clients, - &QListWidget::currentTextChanged, - this, - &LspInspectorWidget::setCurrentClient); - m_clients->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding); + setOrientation(Qt::Horizontal); m_clientDetails = new MessageDetailWidget; m_clientDetails->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_clientDetails->setTitle(tr("Client Message")); - m_serverDetails = new MessageDetailWidget; - m_serverDetails->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - m_serverDetails->setTitle(tr("Server Message")); + addWidget(m_clientDetails); + setStretchFactor(0, 1); m_model.setDataAccessor(&messageData); m_messages = new QListView; m_messages->setModel(&m_model); m_messages->setAlternatingRowColors(true); m_model.setHeader({tr("Messages")}); + m_messages->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); + m_messages->setSelectionMode(QAbstractItemView::MultiSelection); + addWidget(m_messages); + setStretchFactor(1, 0); + + m_serverDetails = new MessageDetailWidget; + m_serverDetails->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_serverDetails->setTitle(tr("Server Message")); + addWidget(m_serverDetails); + setStretchFactor(2, 1); + connect(m_messages->selectionModel(), &QItemSelectionModel::currentChanged, this, - &LspInspectorWidget::currentMessageChanged); - m_messages->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); - m_messages->setSelectionMode(QAbstractItemView::MultiSelection); - - auto layout = new QVBoxLayout; - setLayout(layout); - auto splitter = new Core::MiniSplitter; - splitter->setOrientation(Qt::Horizontal); - splitter->addWidget(m_clients); - splitter->addWidget(m_clientDetails); - splitter->addWidget(m_messages); - splitter->addWidget(m_serverDetails); - splitter->setStretchFactor(0, 0); - splitter->setStretchFactor(1, 1); - splitter->setStretchFactor(2, 1); - splitter->setStretchFactor(3, 1); - layout->addWidget(splitter); - - auto buttonBox = new QDialogButtonBox(this); - buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close); - layout->addWidget(buttonBox); - - // save - connect(buttonBox, &QDialogButtonBox::accepted, this, &LspInspectorWidget::saveLog); - - // close - connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - resize(1024, 768); + &LspLogWidget::currentMessageChanged); } -void LspInspectorWidget::addMessage(const QString &clientName, const LspLogMessage &message) -{ - if (m_clients->findItems(clientName, Qt::MatchExactly).isEmpty()) - m_clients->addItem(clientName); - if (clientName != m_clients->currentItem()->text()) - return; - m_model.appendItem(message); -} - -void LspInspectorWidget::setCurrentClient(const QString &clientName) -{ - m_model.clear(); - for (const LspLogMessage &message : m_inspector->messages(clientName)) - m_model.appendItem(message); -} - -void LspInspectorWidget::currentMessageChanged(const QModelIndex &index) +void LspLogWidget::currentMessageChanged(const QModelIndex &index) { m_messages->clearSelection(); if (!index.isValid()) @@ -247,8 +300,7 @@ static bool matches(LspLogMessage::MessageSender sender, return json.value(QString{idKey}) == id; } -void LspInspectorWidget::selectMatchingMessage(LspLogMessage::MessageSender sender, - const QJsonValue &id) +void LspLogWidget::selectMatchingMessage(LspLogMessage::MessageSender sender, const QJsonValue &id) { LspLogMessage *matchingMessage = m_model.findData( [&](const LspLogMessage &message) { return matches(sender, id, message); }); @@ -264,7 +316,19 @@ void LspInspectorWidget::selectMatchingMessage(LspLogMessage::MessageSender send m_clientDetails->setMessage(matchingMessage->message); } -void LspInspectorWidget::saveLog() +void LspLogWidget::addMessage(const LspLogMessage &message) +{ + m_model.appendItem(message); +} + +void LspLogWidget::setMessages(const std::list &messages) +{ + m_model.clear(); + for (const LspLogMessage &message : messages) + m_model.appendItem(message); +} + +void LspLogWidget::saveLog() { QString contents; QTextStream stream(&contents); @@ -286,6 +350,137 @@ void LspInspectorWidget::saveLog() saveLog(); } +class LspInspectorWidget : public QDialog +{ + Q_DECLARE_TR_FUNCTIONS(LspInspectorWidget) +public: + explicit LspInspectorWidget(LspInspector *inspector); + +private: + void addMessage(const QString &clientName, const LspLogMessage &message); + void updateCapabilities(const QString &clientName); + void setCurrentClient(const QString &clientName); + + LspInspector *m_inspector = nullptr; + LspLogWidget *m_log = nullptr; + LspCapabilitiesWidget *m_capabilities = nullptr; + QListWidget *m_clients = nullptr; +}; + +QWidget *LspInspector::createWidget() +{ + return new LspInspectorWidget(this); +} + +void LspInspector::log(const LspLogMessage::MessageSender sender, + const QString &clientName, + const BaseMessage &message) +{ + std::list &clientLog = m_logs[clientName]; + while (clientLog.size() >= static_cast(m_logSize)) + clientLog.pop_front(); + clientLog.push_back({sender, QTime::currentTime(), message}); + emit newMessage(clientName, clientLog.back()); +} + +void LspInspector::clientInitialized(const QString &clientName, const ServerCapabilities &capabilities) +{ + m_capabilities[clientName].capabilities = capabilities; + m_capabilities[clientName].dynamicCapabilities.reset(); + emit capabilitiesUpdated(clientName); +} + +void LspInspector::updateCapabilities(const QString &clientName, + const DynamicCapabilities &dynamicCapabilities) +{ + m_capabilities[clientName].dynamicCapabilities = dynamicCapabilities; + emit capabilitiesUpdated(clientName); +} + +std::list LspInspector::messages(const QString &clientName) const +{ + return m_logs[clientName]; +} + +Capabilities LspInspector::capabilities(const QString &clientName) const +{ + return m_capabilities.value(clientName); +} + +QList LspInspector::clients() const +{ + return m_logs.keys(); +} + +LspInspectorWidget::LspInspectorWidget(LspInspector *inspector) + : m_inspector(inspector) +{ + setWindowTitle(tr("Language Client Inspector")); + + connect(inspector, &LspInspector::newMessage, this, &LspInspectorWidget::addMessage); + connect(inspector, &LspInspector::capabilitiesUpdated, + this, &LspInspectorWidget::updateCapabilities); + connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close); + + m_clients = new QListWidget; + m_clients->addItems(inspector->clients()); + m_clients->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding); + + auto tabWidget = new QTabWidget; + + auto mainLayout = new QVBoxLayout; + auto mainSplitter = new Core::MiniSplitter; + mainSplitter->setOrientation(Qt::Horizontal); + mainSplitter->addWidget(m_clients); + mainSplitter->addWidget(tabWidget); + mainSplitter->setStretchFactor(0, 0); + mainSplitter->setStretchFactor(1, 1); + m_log = new LspLogWidget; + m_capabilities = new LspCapabilitiesWidget; + tabWidget->addTab(m_log, tr("Log")); + tabWidget->addTab(m_capabilities, tr("Capabilities")); + mainLayout->addWidget(mainSplitter); + + auto buttonBox = new QDialogButtonBox(this); + buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + connect(m_clients, + &QListWidget::currentTextChanged, + this, + &LspInspectorWidget::setCurrentClient); + + // save + connect(buttonBox, &QDialogButtonBox::accepted, m_log, &LspLogWidget::saveLog); + + // close + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + resize(1024, 768); +} + +void LspInspectorWidget::addMessage(const QString &clientName, const LspLogMessage &message) +{ + if (m_clients->findItems(clientName, Qt::MatchExactly).isEmpty()) + m_clients->addItem(clientName); + if (clientName == m_clients->currentItem()->text()) + m_log->addMessage(message); +} + +void LspInspectorWidget::updateCapabilities(const QString &clientName) +{ + if (m_clients->findItems(clientName, Qt::MatchExactly).isEmpty()) + m_clients->addItem(clientName); + if (clientName != m_clients->currentItem()->text()) + m_capabilities->setCapabilities(m_inspector->capabilities(clientName)); +} + +void LspInspectorWidget::setCurrentClient(const QString &clientName) +{ + m_log->setMessages(m_inspector->messages(clientName)); + m_capabilities->setCapabilities(m_inspector->capabilities(clientName)); +} + MessageDetailWidget::MessageDetailWidget() { auto layout = new QFormLayout; @@ -298,26 +493,6 @@ MessageDetailWidget::MessageDetailWidget() layout->addRow("MIME Type:", m_mimeType); } -class JsonTreeItemDelegate : public QStyledItemDelegate -{ -public: - QString displayText(const QVariant &value, const QLocale &) const override - { - QString result = value.toString(); - if (result.size() == 1) { - switch (result.at(0).toLatin1()) { - case '\n': - return QString("\\n"); - case '\t': - return QString("\\t"); - case '\r': - return QString("\\r"); - } - } - return result; - } -}; - void MessageDetailWidget::setMessage(const BaseMessage &message) { m_contentLength->setText(QString::number(message.contentLength)); @@ -327,26 +502,10 @@ void MessageDetailWidget::setMessage(const BaseMessage &message) if (message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType()) { QString error; auto json = JsonRpcMessageHandler::toJsonObject(message.content, message.codec, error); - if (json.isEmpty()) { + if (json.isEmpty()) newContentWidget = new QLabel(error); - } else { - auto root = new Utils::JsonTreeItem("content", json); - if (root->canFetchMore()) - root->fetchMore(); - - auto model = new Utils::TreeModel(root); - model->setHeader({{"Name"}, {"Value"}, {"Type"}}); - auto view = new QTreeView; - view->setContextMenuPolicy(Qt::ActionsContextMenu); - auto action = new QAction(tr("Expand All"), view); - connect(action, &QAction::triggered, view, &QTreeView::expandAll); - view->addAction(action); - view->setModel(model); - view->setAlternatingRowColors(true); - view->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - view->setItemDelegate(new JsonTreeItemDelegate); - newContentWidget = view; - } + else + newContentWidget = createJsonTreeView("content", json); } else { auto edit = new QPlainTextEdit(); edit->setReadOnly(true); diff --git a/src/plugins/languageclient/lspinspector.h b/src/plugins/languageclient/lspinspector.h index 1796adc9643..d69661eccdf 100644 --- a/src/plugins/languageclient/lspinspector.h +++ b/src/plugins/languageclient/lspinspector.h @@ -25,10 +25,13 @@ #pragma once +#include "dynamiccapabilities.h" + #include #include #include +#include #include @@ -41,6 +44,12 @@ struct LspLogMessage LanguageServerProtocol::BaseMessage message; }; +struct Capabilities +{ + LanguageServerProtocol::ServerCapabilities capabilities; + DynamicCapabilities dynamicCapabilities; +}; + class LspInspector : public QObject { Q_OBJECT @@ -53,15 +62,22 @@ public: void log(const LspLogMessage::MessageSender sender, const QString &clientName, const LanguageServerProtocol::BaseMessage &message); + void clientInitialized(const QString &clientName, + const LanguageServerProtocol::ServerCapabilities &capabilities); + void updateCapabilities(const QString &clientName, + const DynamicCapabilities &dynamicCapabilities); std::list messages(const QString &clientName) const; + Capabilities capabilities(const QString &clientName) const; QList clients() const; signals: void newMessage(const QString &clientName, const LspLogMessage &message); + void capabilitiesUpdated(const QString &clientName); private: QMap> m_logs; + QMap m_capabilities; int m_logSize = 100; // default log size if no widget is currently visible };