diff options
Diffstat (limited to 'src/qmlls/qqmllanguageserver.cpp')
-rw-r--r-- | src/qmlls/qqmllanguageserver.cpp | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/src/qmlls/qqmllanguageserver.cpp b/src/qmlls/qqmllanguageserver.cpp new file mode 100644 index 0000000000..1ef142b7b5 --- /dev/null +++ b/src/qmlls/qqmllanguageserver.cpp @@ -0,0 +1,185 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qqmllanguageserver_p.h" +#include "qtextsynchronization_p.h" +#include "qlanguageserver_p.h" +#include "qlspcustomtypes_p.h" + +#include <QtCore/qdir.h> + +#include <iostream> +#include <algorithm> + +QT_BEGIN_NAMESPACE + +namespace QmlLsp { + +using namespace QLspSpecification; +using namespace Qt::StringLiterals; +/*! +\internal +\class QmlLsp::QQmlLanguageServer +\brief Sets up a QmlLanguageServer. + +This class sets up a QML language server. + +Use the following function to send replies: + +\code +std::function<void(const QByteArray &)> sendData +\endcode + +And, feed the data that the function receives to the \c {server()->receive()} +method. + +Call this method only from a single thread, and do not block. To achieve this, +avoid direct calls, and connect the method as a slot, while reading from another +thread. + +The various tasks of the language server are divided between +QLanguageServerModule instances. Each instance is responsible for handling a +certain subset of client requests. For example, one instance handles completion +requests, another one updates the code in the code model when the client sends a +new file version, and so on. The QLanguageServerModule instances are +constructed and registered with QLanguageServer in the constructor of +this class. + +Generally, do all operations in the object thread and always call handlers from +it. However, the operations can delegate the response to another thread, as the +response handler is thread safe. All the methods of the \c server() object are +also thread safe. + +The code model starts other threads to update its state. See its documentation +for more information. +*/ +QQmlLanguageServer::QQmlLanguageServer(std::function<void(const QByteArray &)> sendData, + QQmlToolingSettings *settings) + : m_codeModel(nullptr, settings), + m_server(sendData), + m_textSynchronization(&m_codeModel), + m_lint(&m_server, &m_codeModel), + m_workspace(&m_codeModel), + m_completionSupport(&m_codeModel), + m_navigationSupport(&m_codeModel), + m_definitionSupport(&m_codeModel), + m_referencesSupport(&m_codeModel), + m_documentFormatting(&m_codeModel), + m_renameSupport(&m_codeModel), + m_rangeFormatting(&m_codeModel), + m_hover(&m_codeModel), + m_highlightSupport(&m_codeModel) +{ + m_server.addServerModule(this); + m_server.addServerModule(&m_textSynchronization); + m_server.addServerModule(&m_lint); + m_server.addServerModule(&m_workspace); + m_server.addServerModule(&m_completionSupport); + m_server.addServerModule(&m_navigationSupport); + m_server.addServerModule(&m_definitionSupport); + m_server.addServerModule(&m_referencesSupport); + m_server.addServerModule(&m_documentFormatting); + m_server.addServerModule(&m_renameSupport); + m_server.addServerModule(&m_rangeFormatting); + m_server.addServerModule(&m_hover); + m_server.addServerModule(&m_highlightSupport); + m_server.finishSetup(); + qCWarning(lspServerLog) << "Did Setup"; +} + +void QQmlLanguageServer::registerHandlers(QLanguageServer *server, + QLanguageServerProtocol *protocol) +{ + Q_UNUSED(protocol); + QObject::connect(server, &QLanguageServer::lifecycleError, this, + &QQmlLanguageServer::errorExit); + QObject::connect(server, &QLanguageServer::exit, this, &QQmlLanguageServer::exit); + QObject::connect(server, &QLanguageServer::runStatusChanged, this, [](QLanguageServer::RunStatus r) { + qCDebug(lspServerLog) << "runStatus" << int(r); + }); + protocol->typedRpc()->registerNotificationHandler<Notifications::AddBuildDirsParams>( + QByteArray(Notifications::AddBuildDirsMethod), + [this](const QByteArray &, const Notifications::AddBuildDirsParams ¶ms) { + for (const auto &buildDirs : params.buildDirsToSet) { + QStringList dirPaths; + dirPaths.resize(buildDirs.buildDirs.size()); + std::transform(buildDirs.buildDirs.begin(), buildDirs.buildDirs.end(), + dirPaths.begin(), [](const QByteArray &utf8Str) { + return QString::fromUtf8(utf8Str); + }); + m_codeModel.setBuildPathsForRootUrl(buildDirs.baseUri, dirPaths); + } + }); +} + +void QQmlLanguageServer::setupCapabilities(const QLspSpecification::InitializeParams &clientInfo, + QLspSpecification::InitializeResult &serverInfo) +{ + QJsonObject expCap; + if (serverInfo.capabilities.experimental.has_value() && serverInfo.capabilities.experimental->isObject()) + expCap = serverInfo.capabilities.experimental->toObject(); + expCap.insert(u"addBuildDirs"_s, QJsonObject({ { u"supported"_s, true } })); + serverInfo.capabilities.experimental = expCap; + + if (clientInfo.workspaceFolders) { + if (auto workspaceList = + std::get_if<QList<WorkspaceFolder>>(&*clientInfo.workspaceFolders)) { + QList<QByteArray> workspaceUris; + std::transform(workspaceList->cbegin(), workspaceList->cend(), + std::back_inserter(workspaceUris), + [](const auto &workspaceFolder) { return workspaceFolder.uri; }); + m_codeModel.setRootUrls(workspaceUris); + } + } +} + +QString QQmlLanguageServer::name() const +{ + return u"QQmlLanguageServer"_s; +} + +void QQmlLanguageServer::errorExit() +{ + qCWarning(lspServerLog) << "Error exit"; + fclose(stdin); +} + +void QQmlLanguageServer::exit() +{ + m_returnValue = 0; + fclose(stdin); +} + +int QQmlLanguageServer::returnValue() const +{ + return m_returnValue; +} + +QQmlCodeModel *QQmlLanguageServer::codeModel() +{ + return &m_codeModel; +} + +QLanguageServer *QQmlLanguageServer::server() +{ + return &m_server; +} + +TextSynchronization *QQmlLanguageServer::textSynchronization() +{ + return &m_textSynchronization; +} + +QmlLintSuggestions *QQmlLanguageServer::lint() +{ + return &m_lint; +} + +WorkspaceHandlers *QQmlLanguageServer::worspace() +{ + return &m_workspace; +} + +} // namespace QmlLsp + +QT_END_NAMESPACE |