1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmllanguageserver_p.h"
5#include "qtextsynchronization_p.h"
6#include "qlanguageserver_p.h"
7#include "qlspcustomtypes_p.h"
8
9#include <QtCore/qdir.h>
10
11#include <iostream>
12#include <algorithm>
13
14QT_BEGIN_NAMESPACE
15
16namespace QmlLsp {
17
18using namespace QLspSpecification;
19using namespace Qt::StringLiterals;
20/*!
21\internal
22\class QmlLsp::QQmlLanguageServer
23\brief Sets up a QmlLanguageServer.
24
25This class sets up a QML language server.
26
27Use the following function to send replies:
28
29\code
30std::function<void(const QByteArray &)> sendData
31\endcode
32
33And, feed the data that the function receives to the \c {server()->receive()}
34method.
35
36Call this method only from a single thread, and do not block. To achieve this,
37avoid direct calls, and connect the method as a slot, while reading from another
38thread.
39
40The various tasks of the language server are divided between
41QLanguageServerModule instances. Each instance is responsible for handling a
42certain subset of client requests. For example, one instance handles completion
43requests, another one updates the code in the code model when the client sends a
44new file version, and so on. The QLanguageServerModule instances are
45constructed and registered with QLanguageServer in the constructor of
46this class.
47
48Generally, do all operations in the object thread and always call handlers from
49it. However, the operations can delegate the response to another thread, as the
50response handler is thread safe. All the methods of the \c server() object are
51also thread safe.
52
53The code model starts other threads to update its state. See its documentation
54for more information.
55*/
56QQmlLanguageServer::QQmlLanguageServer(std::function<void(const QByteArray &)> sendData,
57 QQmlToolingSettings *settings)
58 : m_codeModel(nullptr, settings),
59 m_server(sendData),
60 m_textSynchronization(&m_codeModel),
61 m_lint(&m_server, &m_codeModel),
62 m_workspace(&m_codeModel),
63 m_completionSupport(&m_codeModel),
64 m_navigationSupport(&m_codeModel),
65 m_definitionSupport(&m_codeModel),
66 m_referencesSupport(&m_codeModel),
67 m_documentFormatting(&m_codeModel),
68 m_renameSupport(&m_codeModel),
69 m_rangeFormatting(&m_codeModel),
70 m_hover(&m_codeModel),
71 m_highlightSupport(&m_codeModel)
72{
73 m_server.addServerModule(serverModule: this);
74 m_server.addServerModule(serverModule: &m_textSynchronization);
75 m_server.addServerModule(serverModule: &m_lint);
76 m_server.addServerModule(serverModule: &m_workspace);
77 m_server.addServerModule(serverModule: &m_completionSupport);
78 m_server.addServerModule(serverModule: &m_navigationSupport);
79 m_server.addServerModule(serverModule: &m_definitionSupport);
80 m_server.addServerModule(serverModule: &m_referencesSupport);
81 m_server.addServerModule(serverModule: &m_documentFormatting);
82 m_server.addServerModule(serverModule: &m_renameSupport);
83 m_server.addServerModule(serverModule: &m_rangeFormatting);
84 m_server.addServerModule(serverModule: &m_hover);
85 m_server.addServerModule(serverModule: &m_highlightSupport);
86 m_server.finishSetup();
87 qCWarning(lspServerLog) << "Did Setup";
88}
89
90void QQmlLanguageServer::registerHandlers(QLanguageServer *server,
91 QLanguageServerProtocol *protocol)
92{
93 Q_UNUSED(protocol);
94 QObject::connect(sender: server, signal: &QLanguageServer::lifecycleError, context: this,
95 slot: &QQmlLanguageServer::errorExit);
96 QObject::connect(sender: server, signal: &QLanguageServer::exit, context: this, slot: &QQmlLanguageServer::exit);
97 QObject::connect(sender: server, signal: &QLanguageServer::runStatusChanged, context: this, slot: [](QLanguageServer::RunStatus r) {
98 qCDebug(lspServerLog) << "runStatus" << int(r);
99 });
100 protocol->typedRpc()->registerNotificationHandler<Notifications::AddBuildDirsParams>(
101 method: QByteArray(Notifications::AddBuildDirsMethod),
102 handler: [this](const QByteArray &, const Notifications::AddBuildDirsParams &params) {
103 for (const auto &buildDirs : params.buildDirsToSet) {
104 QStringList dirPaths;
105 dirPaths.resize(size: buildDirs.buildDirs.size());
106 std::transform(first: buildDirs.buildDirs.begin(), last: buildDirs.buildDirs.end(),
107 result: dirPaths.begin(), unary_op: [](const QByteArray &utf8Str) {
108 return QString::fromUtf8(ba: utf8Str);
109 });
110 m_codeModel.setBuildPathsForRootUrl(url: buildDirs.baseUri, paths: dirPaths);
111 }
112 });
113}
114
115void QQmlLanguageServer::setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
116 QLspSpecification::InitializeResult &serverInfo)
117{
118 QJsonObject expCap;
119 if (serverInfo.capabilities.experimental.has_value() && serverInfo.capabilities.experimental->isObject())
120 expCap = serverInfo.capabilities.experimental->toObject();
121 expCap.insert(key: u"addBuildDirs"_s, value: QJsonObject({ { u"supported"_s, true } }));
122 serverInfo.capabilities.experimental = expCap;
123
124 if (clientInfo.workspaceFolders) {
125 if (auto workspaceList =
126 std::get_if<QList<WorkspaceFolder>>(ptr: &*clientInfo.workspaceFolders)) {
127 QList<QByteArray> workspaceUris;
128 std::transform(first: workspaceList->cbegin(), last: workspaceList->cend(),
129 result: std::back_inserter(x&: workspaceUris),
130 unary_op: [](const auto &workspaceFolder) { return workspaceFolder.uri; });
131 m_codeModel.setRootUrls(workspaceUris);
132 }
133 }
134}
135
136QString QQmlLanguageServer::name() const
137{
138 return u"QQmlLanguageServer"_s;
139}
140
141void QQmlLanguageServer::errorExit()
142{
143 qCWarning(lspServerLog) << "Error exit";
144 fclose(stdin);
145}
146
147void QQmlLanguageServer::exit()
148{
149 m_returnValue = 0;
150 fclose(stdin);
151}
152
153int QQmlLanguageServer::returnValue() const
154{
155 return m_returnValue;
156}
157
158QQmlCodeModel *QQmlLanguageServer::codeModel()
159{
160 return &m_codeModel;
161}
162
163QLanguageServer *QQmlLanguageServer::server()
164{
165 return &m_server;
166}
167
168TextSynchronization *QQmlLanguageServer::textSynchronization()
169{
170 return &m_textSynchronization;
171}
172
173QmlLintSuggestions *QQmlLanguageServer::lint()
174{
175 return &m_lint;
176}
177
178WorkspaceHandlers *QQmlLanguageServer::worspace()
179{
180 return &m_workspace;
181}
182
183} // namespace QmlLsp
184
185QT_END_NAMESPACE
186

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/qmlls/qqmllanguageserver.cpp