LanguageClient: move capabilities widget to inspector

The capabilities are not changeable for the user, but only there to
check whether a server is capable of a specific task. This will also
allow us to have more specialized settings widgets for specific servers
like for the java language server without the need to add the
capabilities to each of those special widgets.

Also add the dynamic capabilities to the widget so users have a complete
overview of the capabilities.

Change-Id: I9f2ed6ed11b458f0d4c67be3df632fd810023286
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2021-02-11 09:32:11 +01:00
parent c697b503e9
commit f9502a3ba6
8 changed files with 338 additions and 191 deletions

View File

@@ -597,11 +597,13 @@ void Client::registerCapabilities(const QList<Registration> &registrations)
for (auto document : m_openedDocument.keys())
updateFunctionHintProvider(document);
}
emit capabilitiesChanged(m_dynamicCapabilities);
}
void Client::unregisterCapabilities(const QList<Unregistration> &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<const UnregisterCapabilityRequest *>(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) {

View File

@@ -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();

View File

@@ -56,6 +56,11 @@ Utils::optional<bool> 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();

View File

@@ -68,7 +68,8 @@ public:
void unregisterCapability(const QList<LanguageServerProtocol::Unregistration> &unregistrations);
Utils::optional<bool> 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();

View File

@@ -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();

View File

@@ -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<Utils::JsonTreeItem>(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<Client *> 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);

View File

@@ -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<Utils::JsonTreeItem>;
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<LspLogMessage> &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<LspLogMessage> 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<LspLogMessage> &clientLog = m_logs[clientName];
while (clientLog.size() >= static_cast<std::size_t>(m_logSize))
clientLog.pop_front();
clientLog.push_back({sender, QTime::currentTime(), message});
emit newMessage(clientName, clientLog.back());
}
std::list<LspLogMessage> LspInspector::messages(const QString &clientName) const
{
return m_logs[clientName];
}
QList<QString> 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<LspLogMessage> &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<LspLogMessage> &clientLog = m_logs[clientName];
while (clientLog.size() >= static_cast<std::size_t>(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<LspLogMessage> LspInspector::messages(const QString &clientName) const
{
return m_logs[clientName];
}
Capabilities LspInspector::capabilities(const QString &clientName) const
{
return m_capabilities.value(clientName);
}
QList<QString> 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<Utils::JsonTreeItem>(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);

View File

@@ -25,10 +25,13 @@
#pragma once
#include "dynamiccapabilities.h"
#include <QTime>
#include <QWidget>
#include <languageserverprotocol/basemessage.h>
#include <languageserverprotocol/servercapabilities.h>
#include <list>
@@ -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<LspLogMessage> messages(const QString &clientName) const;
Capabilities capabilities(const QString &clientName) const;
QList<QString> clients() const;
signals:
void newMessage(const QString &clientName, const LspLogMessage &message);
void capabilitiesUpdated(const QString &clientName);
private:
QMap<QString, std::list<LspLogMessage>> m_logs;
QMap<QString, Capabilities> m_capabilities;
int m_logSize = 100; // default log size if no widget is currently visible
};