forked from qt-creator/qt-creator
LanguageClient: Move the BaseMessage to JsonRpcMessage conversion
... to the client interface. JsonRpcMessages are the only messages used so far and no other types of messages are currently used by any of the supported Language Servers. If a client is going to need special message parsing it can still implement a specialized client interface and overwrite parseCurrentMessage. This is the preparation to move receiving and parsing data passed to and from the language server out of the GUI thread. Change-Id: Ibd4cd95daab7efff947273ca9e7d457de0286f47 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -38,12 +38,12 @@ namespace LanguageServerProtocol {
|
||||
Q_LOGGING_CATEGORY(parseLog, "qtc.languageserverprotocol.parse", QtWarningMsg)
|
||||
|
||||
BaseMessage::BaseMessage()
|
||||
: mimeType(JsonRpcMessageHandler::jsonRpcMimeType())
|
||||
: mimeType(JsonRpcMessage::jsonRpcMimeType())
|
||||
{ }
|
||||
|
||||
BaseMessage::BaseMessage(const QByteArray &mimeType, const QByteArray &content,
|
||||
int expectedLength, QTextCodec *codec)
|
||||
: mimeType(mimeType.isEmpty() ? JsonRpcMessageHandler::jsonRpcMimeType() : mimeType)
|
||||
: mimeType(mimeType.isEmpty() ? JsonRpcMessage::jsonRpcMimeType() : mimeType)
|
||||
, content(content)
|
||||
, contentLength(expectedLength)
|
||||
, codec(codec)
|
||||
@@ -177,7 +177,7 @@ QByteArray BaseMessage::header() const
|
||||
QByteArray header;
|
||||
header.append(lengthHeader());
|
||||
if (codec != defaultCodec()
|
||||
|| (!mimeType.isEmpty() && mimeType != JsonRpcMessageHandler::jsonRpcMimeType())) {
|
||||
|| (!mimeType.isEmpty() && mimeType != JsonRpcMessage::jsonRpcMimeType())) {
|
||||
header.append(typeHeader());
|
||||
}
|
||||
header.append(headerSeparator);
|
||||
|
@@ -47,11 +47,16 @@ QByteArray JsonRpcMessage::toRawData() const
|
||||
|
||||
QByteArray JsonRpcMessage::mimeType() const
|
||||
{
|
||||
return JsonRpcMessageHandler::jsonRpcMimeType();
|
||||
return jsonRpcMimeType();
|
||||
}
|
||||
|
||||
bool JsonRpcMessage::isValid(QString * /*errorMessage*/) const
|
||||
bool JsonRpcMessage::isValid(QString *errorMessage) const
|
||||
{
|
||||
if (!m_parseError.isEmpty()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = m_parseError;
|
||||
return false;
|
||||
}
|
||||
return m_jsonObject[jsonRpcVersionKey] == "2.0";
|
||||
}
|
||||
|
||||
@@ -66,38 +71,6 @@ JsonRpcMessage::JsonRpcMessage()
|
||||
m_jsonObject[jsonRpcVersionKey] = "2.0";
|
||||
}
|
||||
|
||||
JsonRpcMessage::JsonRpcMessage(const QJsonObject &jsonObject)
|
||||
: m_jsonObject(jsonObject)
|
||||
{ }
|
||||
|
||||
JsonRpcMessage::JsonRpcMessage(QJsonObject &&jsonObject)
|
||||
: m_jsonObject(std::move(jsonObject))
|
||||
{ }
|
||||
|
||||
QByteArray JsonRpcMessageHandler::jsonRpcMimeType()
|
||||
{
|
||||
return "application/vscode-jsonrpc";
|
||||
}
|
||||
|
||||
void JsonRpcMessageHandler::parseContent(const QByteArray &content,
|
||||
QTextCodec *codec,
|
||||
QString &parseError,
|
||||
const ResponseHandlers &responseHandlers,
|
||||
const MethodHandler &methodHandler)
|
||||
{
|
||||
const QJsonObject &jsonObject = toJsonObject(content, codec, parseError);
|
||||
if (jsonObject.isEmpty())
|
||||
return;
|
||||
|
||||
const MessageId id(jsonObject.value(idKey));
|
||||
const QString &method = jsonObject.value(methodKey).toString();
|
||||
const JsonRpcMessage jsonContent(jsonObject);
|
||||
if (method.isEmpty())
|
||||
responseHandlers(id, jsonContent);
|
||||
else
|
||||
methodHandler(method, id, jsonContent);
|
||||
}
|
||||
|
||||
constexpr int utf8mib = 106;
|
||||
|
||||
static QString docTypeName(const QJsonDocument &doc)
|
||||
@@ -113,29 +86,43 @@ static QString docTypeName(const QJsonDocument &doc)
|
||||
return {};
|
||||
}
|
||||
|
||||
QJsonObject JsonRpcMessageHandler::toJsonObject(const QByteArray &_content,
|
||||
QTextCodec *codec,
|
||||
QString &parseError)
|
||||
JsonRpcMessage::JsonRpcMessage(const BaseMessage &message)
|
||||
{
|
||||
if (_content.isEmpty())
|
||||
return QJsonObject();
|
||||
if (message.content.isEmpty())
|
||||
return;
|
||||
QByteArray content;
|
||||
if (codec && codec->mibEnum() != utf8mib) {
|
||||
if (message.codec && message.codec->mibEnum() != utf8mib) {
|
||||
QTextCodec *utf8 = QTextCodec::codecForMib(utf8mib);
|
||||
if (utf8)
|
||||
content = utf8->fromUnicode(codec->toUnicode(_content));
|
||||
content = utf8->fromUnicode(message.codec->toUnicode(message.content));
|
||||
}
|
||||
if (content.isEmpty())
|
||||
content = _content;
|
||||
QJsonParseError error = {0 , QJsonParseError::NoError};
|
||||
content = message.content;
|
||||
QJsonParseError error = {0, QJsonParseError::NoError};
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(content, &error);
|
||||
if (doc.isObject())
|
||||
return doc.object();
|
||||
if (doc.isNull())
|
||||
parseError = tr("Could not parse JSON message \"%1\".").arg(error.errorString());
|
||||
else
|
||||
parseError = tr("Expected a JSON object, but got a JSON \"%1\" value.").arg(docTypeName(doc));
|
||||
return QJsonObject();
|
||||
if (doc.isObject()) {
|
||||
m_jsonObject = doc.object();
|
||||
} else if (doc.isNull()) {
|
||||
m_parseError = tr("LanguageServerProtocol::JsonRpcMessage",
|
||||
"Could not parse JSON message \"%1\".")
|
||||
.arg(error.errorString());
|
||||
} else {
|
||||
m_parseError = tr("Expected a JSON object, but got a JSON \"%1\" value.")
|
||||
.arg(docTypeName(doc));
|
||||
}
|
||||
}
|
||||
|
||||
JsonRpcMessage::JsonRpcMessage(const QJsonObject &jsonObject)
|
||||
: m_jsonObject(jsonObject)
|
||||
{ }
|
||||
|
||||
JsonRpcMessage::JsonRpcMessage(QJsonObject &&jsonObject)
|
||||
: m_jsonObject(std::move(jsonObject))
|
||||
{ }
|
||||
|
||||
QByteArray JsonRpcMessage::jsonRpcMimeType()
|
||||
{
|
||||
return "application/vscode-jsonrpc";
|
||||
}
|
||||
|
||||
CancelRequest::CancelRequest(const CancelParameter ¶ms)
|
||||
|
@@ -45,16 +45,23 @@ namespace LanguageServerProtocol {
|
||||
|
||||
class LANGUAGESERVERPROTOCOL_EXPORT JsonRpcMessage : public IContent
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(JsonRpcMessage)
|
||||
public:
|
||||
JsonRpcMessage();
|
||||
explicit JsonRpcMessage(const BaseMessage &message);
|
||||
explicit JsonRpcMessage(const QJsonObject &jsonObject);
|
||||
explicit JsonRpcMessage(QJsonObject &&jsonObject);
|
||||
|
||||
static QByteArray jsonRpcMimeType();
|
||||
|
||||
QByteArray toRawData() const final;
|
||||
QByteArray mimeType() const final;
|
||||
bool isValid(QString *errorMessage) const override;
|
||||
|
||||
const QJsonObject &toJsonObject() const;
|
||||
|
||||
const QString parseError() { return m_parseError; }
|
||||
|
||||
protected:
|
||||
QJsonObject m_jsonObject;
|
||||
|
||||
@@ -62,18 +69,6 @@ private:
|
||||
QString m_parseError;
|
||||
};
|
||||
|
||||
class LANGUAGESERVERPROTOCOL_EXPORT JsonRpcMessageHandler
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(JsonRpcMessageHandler)
|
||||
|
||||
public:
|
||||
static QByteArray jsonRpcMimeType();
|
||||
static void parseContent(const QByteArray &content, QTextCodec *codec, QString &errorMessage,
|
||||
const ResponseHandlers &responseHandlers,
|
||||
const MethodHandler &methodHandler);
|
||||
static QJsonObject toJsonObject(const QByteArray &content, QTextCodec *codec, QString &parseError);
|
||||
};
|
||||
|
||||
template <typename Params>
|
||||
class Notification : public JsonRpcMessage
|
||||
{
|
||||
|
@@ -104,10 +104,8 @@ Client::Client(BaseClientInterface *clientInterface)
|
||||
connect(SessionManager::instance(), &SessionManager::projectRemoved,
|
||||
this, &Client::projectClosed);
|
||||
|
||||
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
|
||||
&JsonRpcMessageHandler::parseContent);
|
||||
QTC_ASSERT(clientInterface, return);
|
||||
connect(clientInterface, &BaseClientInterface::messageReceived, this, &Client::handleMessage);
|
||||
connect(clientInterface, &BaseClientInterface::contentReceived, this, &Client::handleContent);
|
||||
connect(clientInterface, &BaseClientInterface::error, this, &Client::setError);
|
||||
connect(clientInterface, &BaseClientInterface::finished, this, &Client::finished);
|
||||
connect(Core::EditorManager::instance(),
|
||||
@@ -161,8 +159,8 @@ Client::~Client()
|
||||
m_documentHighlightsTimer.clear();
|
||||
updateEditorToolBar(m_openedDocument.keys());
|
||||
// do not handle messages while shutting down
|
||||
disconnect(m_clientInterface.data(), &BaseClientInterface::messageReceived,
|
||||
this, &Client::handleMessage);
|
||||
disconnect(m_clientInterface.data(), &BaseClientInterface::contentReceived,
|
||||
this, &Client::handleContent);
|
||||
delete m_diagnosticManager;
|
||||
}
|
||||
|
||||
@@ -327,8 +325,8 @@ void Client::initialize()
|
||||
if (Utils::optional<ResponseHandler> responseHandler = initRequest.responseHandler())
|
||||
m_responseHandlers[responseHandler->id] = responseHandler->callback;
|
||||
|
||||
// directly send message otherwise the state check of sendContent would fail
|
||||
sendMessage(initRequest.toBaseMessage());
|
||||
// directly send content now otherwise the state check of sendContent would fail
|
||||
sendContentNow(initRequest);
|
||||
m_state = InitializeRequested;
|
||||
}
|
||||
|
||||
@@ -444,7 +442,7 @@ void Client::sendContent(const IContent &content, SendDocUpdates sendUpdates)
|
||||
QString error;
|
||||
if (!QTC_GUARD(content.isValid(&error)))
|
||||
Core::MessageManager::writeFlashing(error);
|
||||
sendMessage(content.toBaseMessage());
|
||||
sendContentNow(content);
|
||||
}
|
||||
|
||||
void Client::cancelRequest(const MessageId &id)
|
||||
@@ -1218,23 +1216,15 @@ void Client::setProgressTitleForToken(const LanguageServerProtocol::ProgressToke
|
||||
m_progressManager.setTitleForToken(token, message);
|
||||
}
|
||||
|
||||
void Client::handleMessage(const BaseMessage &message)
|
||||
void Client::handleContent(const LanguageServerProtocol::JsonRpcMessage &message)
|
||||
{
|
||||
LanguageClientManager::logBaseMessage(LspLogMessage::ServerMessage, name(), message);
|
||||
if (auto handler = m_contentHandler[message.mimeType]) {
|
||||
QString parseError;
|
||||
handler(message.content, message.codec, parseError,
|
||||
[this](const MessageId &id, const IContent &content){
|
||||
this->handleResponse(id, content);
|
||||
},
|
||||
[this](const QString &method, const MessageId &id, const IContent &content){
|
||||
this->handleMethod(method, id, content);
|
||||
});
|
||||
if (!parseError.isEmpty())
|
||||
log(parseError);
|
||||
} else {
|
||||
log(tr("Cannot handle content of type: %1").arg(QLatin1String(message.mimeType)));
|
||||
}
|
||||
LanguageClientManager::logJsonRpcMessage(LspLogMessage::ServerMessage, name(), message);
|
||||
const MessageId id(message.toJsonObject().value(idKey));
|
||||
const QString method = message.toJsonObject().value(methodKey).toString();
|
||||
if (method.isEmpty())
|
||||
handleResponse(id, message);
|
||||
else
|
||||
handleMethod(method, id, message);
|
||||
}
|
||||
|
||||
void Client::log(const QString &message) const
|
||||
@@ -1544,10 +1534,14 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::sendMessage(const BaseMessage &message)
|
||||
void Client::sendContentNow(const IContent &content)
|
||||
{
|
||||
LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage, name(), message);
|
||||
m_clientInterface->sendMessage(message);
|
||||
if (content.mimeType() == JsonRpcMessage::jsonRpcMimeType()) {
|
||||
LanguageClientManager::logJsonRpcMessage(LspLogMessage::ClientMessage,
|
||||
name(),
|
||||
static_cast<const JsonRpcMessage &>(content));
|
||||
}
|
||||
m_clientInterface->sendContent(content);
|
||||
}
|
||||
|
||||
bool Client::documentUpdatePostponed(const Utils::FilePath &fileName) const
|
||||
@@ -1663,8 +1657,8 @@ void Client::shutDownCallback(const ShutdownRequest::Response &shutdownResponse)
|
||||
QTC_ASSERT(m_clientInterface, return);
|
||||
if (optional<ShutdownRequest::Response::Error> error = shutdownResponse.error())
|
||||
log(*error);
|
||||
// directly send message otherwise the state check of sendContent would fail
|
||||
sendMessage(ExitNotification().toBaseMessage());
|
||||
// directly send content now otherwise the state check of sendContent would fail
|
||||
sendContentNow(ExitNotification());
|
||||
qCDebug(LOGLSPCLIENT) << "language server " << m_displayName << " shutdown";
|
||||
m_state = Shutdown;
|
||||
m_shutdownTimer.start();
|
||||
|
@@ -225,12 +225,12 @@ protected:
|
||||
void setError(const QString &message);
|
||||
void setProgressTitleForToken(const LanguageServerProtocol::ProgressToken &token,
|
||||
const QString &message);
|
||||
void handleMessage(const LanguageServerProtocol::BaseMessage &message);
|
||||
void handleContent(const LanguageServerProtocol::JsonRpcMessage &message);
|
||||
virtual void handleDiagnostics(const LanguageServerProtocol::PublishDiagnosticsParams ¶ms);
|
||||
virtual DiagnosticManager *createDiagnosticManager();
|
||||
|
||||
private:
|
||||
void sendMessage(const LanguageServerProtocol::BaseMessage &message);
|
||||
void sendContentNow(const LanguageServerProtocol::IContent &content);
|
||||
void handleResponse(const LanguageServerProtocol::MessageId &id,
|
||||
const LanguageServerProtocol::IContent &content);
|
||||
void handleMethod(const QString &method,
|
||||
@@ -274,7 +274,6 @@ private:
|
||||
State m_state = Uninitialized;
|
||||
QHash<LanguageServerProtocol::MessageId,
|
||||
LanguageServerProtocol::ResponseHandler::Callback> m_responseHandlers;
|
||||
QHash<QByteArray, ContentHandler> m_contentHandler;
|
||||
QString m_displayName;
|
||||
LanguageFilter m_languagFilter;
|
||||
QJsonObject m_initializationOptions;
|
||||
|
@@ -46,8 +46,9 @@ BaseClientInterface::~BaseClientInterface()
|
||||
m_buffer.close();
|
||||
}
|
||||
|
||||
void BaseClientInterface::sendMessage(const BaseMessage &message)
|
||||
void BaseClientInterface::sendContent(const IContent &content)
|
||||
{
|
||||
const BaseMessage message = content.toBaseMessage();
|
||||
sendData(message.header());
|
||||
sendData(message.content);
|
||||
}
|
||||
@@ -78,8 +79,7 @@ void BaseClientInterface::parseData(const QByteArray &data)
|
||||
emit error(parseError);
|
||||
if (!m_currentMessage.isComplete())
|
||||
break;
|
||||
emit messageReceived(m_currentMessage);
|
||||
m_currentMessage = BaseMessage();
|
||||
parseCurrentMessage();
|
||||
}
|
||||
if (m_buffer.atEnd()) {
|
||||
m_buffer.close();
|
||||
@@ -88,6 +88,17 @@ void BaseClientInterface::parseData(const QByteArray &data)
|
||||
}
|
||||
}
|
||||
|
||||
void BaseClientInterface::parseCurrentMessage()
|
||||
{
|
||||
if (m_currentMessage.mimeType == JsonRpcMessage::jsonRpcMimeType()) {
|
||||
emit contentReceived(JsonRpcMessage(m_currentMessage));
|
||||
} else {
|
||||
emit error(tr("Cannot handle mimetype of message %1")
|
||||
.arg(QString::fromUtf8(m_currentMessage.mimeType)));
|
||||
}
|
||||
m_currentMessage = BaseMessage();
|
||||
}
|
||||
|
||||
StdIOClientInterface::StdIOClientInterface()
|
||||
{
|
||||
m_process.setProcessMode(ProcessMode::Writer);
|
||||
|
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "languageclient_global.h"
|
||||
|
||||
#include <languageserverprotocol/basemessage.h>
|
||||
#include <languageserverprotocol/jsonrpcmessages.h>
|
||||
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
@@ -45,19 +45,20 @@ public:
|
||||
|
||||
~BaseClientInterface() override;
|
||||
|
||||
void sendMessage(const LanguageServerProtocol::BaseMessage &message);
|
||||
void sendContent(const LanguageServerProtocol::IContent &content);
|
||||
virtual bool start() { return true; }
|
||||
|
||||
void resetBuffer();
|
||||
|
||||
signals:
|
||||
void messageReceived(LanguageServerProtocol::BaseMessage message);
|
||||
void contentReceived(const LanguageServerProtocol::JsonRpcMessage message);
|
||||
void finished();
|
||||
void error(const QString &message);
|
||||
|
||||
protected:
|
||||
virtual void sendData(const QByteArray &data) = 0;
|
||||
void parseData(const QByteArray &data);
|
||||
virtual void parseCurrentMessage();
|
||||
|
||||
private:
|
||||
QBuffer m_buffer;
|
||||
|
@@ -424,9 +424,9 @@ void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *doc
|
||||
TextEditor::IOutlineWidgetFactory::updateOutline();
|
||||
}
|
||||
|
||||
void LanguageClientManager::logBaseMessage(const LspLogMessage::MessageSender sender,
|
||||
void LanguageClientManager::logJsonRpcMessage(const LspLogMessage::MessageSender sender,
|
||||
const QString &clientName,
|
||||
const BaseMessage &message)
|
||||
const LanguageServerProtocol::JsonRpcMessage &message)
|
||||
{
|
||||
instance()->m_inspector.log(sender, clientName, message);
|
||||
}
|
||||
|
@@ -96,9 +96,10 @@ public:
|
||||
///
|
||||
static void openDocumentWithClient(TextEditor::TextDocument *document, Client *client);
|
||||
|
||||
static void logBaseMessage(const LspLogMessage::MessageSender sender,
|
||||
static void logJsonRpcMessage(const LspLogMessage::MessageSender sender,
|
||||
const QString &clientName,
|
||||
const LanguageServerProtocol::BaseMessage &message);
|
||||
const LanguageServerProtocol::JsonRpcMessage &message);
|
||||
|
||||
static void showInspector();
|
||||
|
||||
signals:
|
||||
|
@@ -120,8 +120,7 @@ public:
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QLabel *m_contentLength = nullptr;
|
||||
QLabel *m_mimeType = nullptr;
|
||||
QTreeView *m_jsonTree = nullptr;
|
||||
};
|
||||
|
||||
class LspCapabilitiesWidget : public QWidget
|
||||
@@ -258,8 +257,11 @@ LspLogWidget::LspLogWidget()
|
||||
void LspLogWidget::currentMessageChanged(const QModelIndex &index)
|
||||
{
|
||||
m_messages->clearSelection();
|
||||
if (!index.isValid())
|
||||
if (!index.isValid()) {
|
||||
m_clientDetails->clear();
|
||||
m_serverDetails->clear();
|
||||
return;
|
||||
}
|
||||
LspLogMessage message = m_model.itemAt(index.row())->itemData;
|
||||
if (message.sender == LspLogMessage::ClientMessage)
|
||||
m_clientDetails->setMessage(message);
|
||||
@@ -274,8 +276,6 @@ static bool matches(LspLogMessage::MessageSender sender,
|
||||
{
|
||||
if (message.sender != sender)
|
||||
return false;
|
||||
if (message.message.mimeType != JsonRpcMessageHandler::jsonRpcMimeType())
|
||||
return false;
|
||||
return message.id() == id;
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ void LspLogWidget::saveLog()
|
||||
stream << (message.sender == LspLogMessage::ClientMessage ? QString{"Client"}
|
||||
: QString{"Server"});
|
||||
stream << '\n';
|
||||
stream << message.message.codec->toUnicode(message.message.content);
|
||||
stream << QJsonDocument(message.message.toJsonObject()).toJson();
|
||||
stream << "\n\n";
|
||||
});
|
||||
|
||||
@@ -365,7 +365,7 @@ QWidget *LspInspector::createWidget(const QString &defaultClient)
|
||||
|
||||
void LspInspector::log(const LspLogMessage::MessageSender sender,
|
||||
const QString &clientName,
|
||||
const BaseMessage &message)
|
||||
const JsonRpcMessage &message)
|
||||
{
|
||||
std::list<LspLogMessage> &clientLog = m_logs[clientName];
|
||||
while (clientLog.size() >= static_cast<std::size_t>(m_logSize))
|
||||
@@ -510,50 +510,27 @@ LspCapabilitiesWidget *LspInspectorWidget::capabilities() const
|
||||
|
||||
MessageDetailWidget::MessageDetailWidget()
|
||||
{
|
||||
auto layout = new QFormLayout;
|
||||
auto layout = new QVBoxLayout;
|
||||
setLayout(layout);
|
||||
|
||||
m_contentLength = new QLabel;
|
||||
m_mimeType = new QLabel;
|
||||
m_jsonTree = new QTreeView;
|
||||
|
||||
layout->addRow("Content Length:", m_contentLength);
|
||||
layout->addRow("MIME Type:", m_mimeType);
|
||||
layout->addWidget(m_jsonTree);
|
||||
}
|
||||
|
||||
void MessageDetailWidget::setMessage(const LspLogMessage &message)
|
||||
{
|
||||
m_contentLength->setText(QString::number(message.message.contentLength));
|
||||
m_mimeType->setText(QString::fromLatin1(message.message.mimeType));
|
||||
|
||||
QWidget *newContentWidget = nullptr;
|
||||
if (message.message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType()) {
|
||||
newContentWidget = createJsonTreeView("content", message.json());
|
||||
} else {
|
||||
auto edit = new QPlainTextEdit();
|
||||
edit->setReadOnly(true);
|
||||
edit->setPlainText(message.message.codec->toUnicode(message.message.content));
|
||||
newContentWidget = edit;
|
||||
}
|
||||
auto formLayout = static_cast<QFormLayout *>(layout());
|
||||
if (formLayout->rowCount() > 2)
|
||||
formLayout->removeRow(2);
|
||||
formLayout->setWidget(2, QFormLayout::SpanningRole, newContentWidget);
|
||||
m_jsonTree->setModel(createJsonModel("content", message.message.toJsonObject()));
|
||||
}
|
||||
|
||||
void MessageDetailWidget::clear()
|
||||
{
|
||||
m_contentLength->setText({});
|
||||
m_mimeType->setText({});
|
||||
auto formLayout = static_cast<QFormLayout *>(layout());
|
||||
if (formLayout->rowCount() > 2)
|
||||
formLayout->removeRow(2);
|
||||
m_jsonTree->setModel(createJsonModel("", QJsonObject()));
|
||||
}
|
||||
|
||||
LspLogMessage::LspLogMessage() = default;
|
||||
|
||||
LspLogMessage::LspLogMessage(MessageSender sender,
|
||||
const QTime &time,
|
||||
const LanguageServerProtocol::BaseMessage &message)
|
||||
LspLogMessage::LspLogMessage(MessageSender sender, const QTime &time, const JsonRpcMessage &message)
|
||||
: sender(sender)
|
||||
, time(time)
|
||||
, message(message)
|
||||
@@ -562,7 +539,7 @@ LspLogMessage::LspLogMessage(MessageSender sender,
|
||||
MessageId LspLogMessage::id() const
|
||||
{
|
||||
if (!m_id.has_value())
|
||||
m_id = MessageId(json().value(idKey));
|
||||
m_id = MessageId(message.toJsonObject().value(idKey));
|
||||
return *m_id;
|
||||
}
|
||||
|
||||
@@ -570,25 +547,10 @@ QString LspLogMessage::displayText() const
|
||||
{
|
||||
if (!m_displayText.has_value()) {
|
||||
m_displayText = QString(time.toString("hh:mm:ss.zzz") + '\n');
|
||||
if (message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType())
|
||||
m_displayText->append(json().value(QString{methodKey}).toString(id().toString()));
|
||||
else
|
||||
m_displayText->append(message.codec->toUnicode(message.content));
|
||||
m_displayText->append(
|
||||
message.toJsonObject().value(QString{methodKey}).toString(id().toString()));
|
||||
}
|
||||
return *m_displayText;
|
||||
}
|
||||
|
||||
QJsonObject &LspLogMessage::json() const
|
||||
{
|
||||
if (!m_json.has_value()) {
|
||||
if (message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType()) {
|
||||
QString error;
|
||||
m_json = JsonRpcMessageHandler::toJsonObject(message.content, message.codec, error);
|
||||
} else {
|
||||
m_json = QJsonObject();
|
||||
}
|
||||
}
|
||||
return *m_json;
|
||||
}
|
||||
|
||||
} // namespace LanguageClient
|
||||
|
@@ -45,18 +45,16 @@ public:
|
||||
LspLogMessage();
|
||||
LspLogMessage(MessageSender sender,
|
||||
const QTime &time,
|
||||
const LanguageServerProtocol::BaseMessage &message);
|
||||
const LanguageServerProtocol::JsonRpcMessage &message);
|
||||
QTime time;
|
||||
LanguageServerProtocol::BaseMessage message;
|
||||
LanguageServerProtocol::JsonRpcMessage message;
|
||||
|
||||
LanguageServerProtocol::MessageId id() const;
|
||||
QString displayText() const;
|
||||
QJsonObject &json() const;
|
||||
|
||||
private:
|
||||
mutable Utils::optional<LanguageServerProtocol::MessageId> m_id;
|
||||
mutable Utils::optional<QString> m_displayText;
|
||||
mutable Utils::optional<QJsonObject> m_json;
|
||||
};
|
||||
|
||||
struct Capabilities
|
||||
@@ -76,7 +74,7 @@ public:
|
||||
|
||||
void log(const LspLogMessage::MessageSender sender,
|
||||
const QString &clientName,
|
||||
const LanguageServerProtocol::BaseMessage &message);
|
||||
const LanguageServerProtocol::JsonRpcMessage &message);
|
||||
void clientInitialized(const QString &clientName,
|
||||
const LanguageServerProtocol::ServerCapabilities &capabilities);
|
||||
void updateCapabilities(const QString &clientName,
|
||||
|
@@ -72,7 +72,7 @@ private:
|
||||
|
||||
void tst_LanguageServerProtocol::initTestCase()
|
||||
{
|
||||
defaultMimeType = JsonRpcMessageHandler::jsonRpcMimeType();
|
||||
defaultMimeType = JsonRpcMessage::jsonRpcMimeType();
|
||||
defaultCodec = QTextCodec::codecForName("utf-8");
|
||||
}
|
||||
|
||||
@@ -447,13 +447,13 @@ void tst_LanguageServerProtocol::toJsonObject()
|
||||
QFETCH(bool, error);
|
||||
QFETCH(QJsonObject, expected);
|
||||
|
||||
QString parseError;
|
||||
const QJsonObject object = JsonRpcMessageHandler::toJsonObject(content, codec, parseError);
|
||||
BaseMessage baseMessage(JsonRpcMessage::jsonRpcMimeType(), content, content.length(), codec);
|
||||
JsonRpcMessage jsonRpcMessage(baseMessage);
|
||||
|
||||
if (!error && !parseError.isEmpty())
|
||||
QFAIL(parseError.toLocal8Bit().data());
|
||||
QCOMPARE(object, expected);
|
||||
QCOMPARE(!parseError.isEmpty(), error);
|
||||
if (!error && !jsonRpcMessage.parseError().isEmpty())
|
||||
QFAIL(jsonRpcMessage.parseError().toLocal8Bit().data());
|
||||
QCOMPARE(jsonRpcMessage.toJsonObject(), expected);
|
||||
QCOMPARE(!jsonRpcMessage.parseError().isEmpty(), error);
|
||||
}
|
||||
|
||||
void tst_LanguageServerProtocol::jsonMessageToBaseMessage_data()
|
||||
@@ -462,11 +462,11 @@ void tst_LanguageServerProtocol::jsonMessageToBaseMessage_data()
|
||||
QTest::addColumn<BaseMessage>("baseMessage");
|
||||
|
||||
QTest::newRow("empty object") << JsonRpcMessage(QJsonObject())
|
||||
<< BaseMessage(JsonRpcMessageHandler::jsonRpcMimeType(),
|
||||
<< BaseMessage(JsonRpcMessage::jsonRpcMimeType(),
|
||||
"{}");
|
||||
|
||||
QTest::newRow("key value pair") << JsonRpcMessage({{"key", "value"}})
|
||||
<< BaseMessage(JsonRpcMessageHandler::jsonRpcMimeType(),
|
||||
QTest::newRow("key value pair") << JsonRpcMessage(QJsonObject{{"key", "value"}})
|
||||
<< BaseMessage(JsonRpcMessage::jsonRpcMimeType(),
|
||||
R"({"key":"value"})");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user