Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qworkspace.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#include "qworkspace_p.h"
8
9#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
10#include <QtLanguageServer/private/qlspnotifysignals_p.h>
11
12#include <QtCore/qfile.h>
13#include <variant>
14
16using namespace Qt::StringLiterals;
17using namespace QLspSpecification;
18
19void WorkspaceHandlers::registerHandlers(QLanguageServer *server, QLanguageServerProtocol *)
20{
21 QObject::connect(server->notifySignals(),
22 &QLspNotifySignals::receivedDidChangeWorkspaceFoldersNotification, this,
23 [this](const DidChangeWorkspaceFoldersParams &params) {
24 const WorkspaceFoldersChangeEvent &event = params.event;
25
26 const QList<WorkspaceFolder> &removed = event.removed;
27 QList<QByteArray> toRemove;
28 for (const WorkspaceFolder &folder : removed) {
29 toRemove.append(QQmlLSUtils::lspUriToQmlUrl(folder.uri));
30 m_codeModelManager->removeDirectory(
31 QQmlLSUtils::lspUriToQmlUrl(folder.uri));
32 }
33 m_codeModelManager->removeRootUrls(toRemove);
34 const QList<WorkspaceFolder> &added = event.added;
35 QList<QByteArray> toAdd;
36 for (const WorkspaceFolder &folder : added) {
37 toAdd.append(QQmlLSUtils::lspUriToQmlUrl(folder.uri));
38 }
39 m_codeModelManager->addRootUrls(toAdd);
40 });
41
42 QObject::connect(server, &QLanguageServer::clientInitialized, this,
43 &WorkspaceHandlers::clientInitialized);
44}
45
46QString WorkspaceHandlers::name() const
47{
48 return u"Workspace"_s;
49}
50
51void WorkspaceHandlers::setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
52 QLspSpecification::InitializeResult &serverInfo)
53{
54 if (!clientInfo.capabilities.workspace
55 || !clientInfo.capabilities.workspace->value(u"workspaceFolders"_s).toBool(false))
56 return;
57 WorkspaceFoldersServerCapabilities folders;
58 folders.supported = true;
59 folders.changeNotifications = true;
60 if (!serverInfo.capabilities.workspace)
61 serverInfo.capabilities.workspace = QJsonObject();
62 serverInfo.capabilities.workspace->insert(u"workspaceFolders"_s,
63 QTypedJson::toJsonValue(folders));
64
65 openInitialWorkspace(clientInfo);
66}
67
68void WorkspaceHandlers::openInitialWorkspace(const InitializeParams &clientInfo)
69{
70 if (clientInfo.workspaceFolders) {
71 const auto *folders = std::get_if<QList<WorkspaceFolder>>(&*clientInfo.workspaceFolders);
72
73 // note: if *clientInfo.workspaceFolders contains a nullptr_t than it means that no WS was
74 // opened yet.
75 if (!folders)
76 return;
77
78 QList<QByteArray> rootPaths;
79 for (const auto &folder : std::as_const(*folders)) {
80 rootPaths.append(QQmlLSUtils::lspUriToQmlUrl(folder.uri));
81 }
82 m_codeModelManager->addRootUrls(rootPaths);
83 return;
84 }
85
86 // note: rootUri is deprecated in the LSP protocol
87 if (const auto *rootUri = std::get_if<QByteArray>(&clientInfo.rootUri)) {
88 m_codeModelManager->addRootUrls({ QQmlLSUtils::lspUriToQmlUrl(*rootUri) });
89 return;
90 }
91 // note: rootPath is also deprecated in the LSP protocol. It was deprecated even before rootUri
92 // was deprecated.
93 if (clientInfo.rootPath) {
94 if (const auto *rootPath = std::get_if<QByteArray>(&*clientInfo.rootPath)) {
95 m_codeModelManager->addRootUrls({
96 QUrl::fromLocalFile(QString::fromUtf8(*rootPath)).toEncoded(),
97 });
98 return;
99 }
100 }
101}
102
103void WorkspaceHandlers::clientInitialized(QLanguageServer *server)
104{
105 QLanguageServerProtocol *protocol = server->protocol();
106 const auto clientInfo = server->clientInfo();
107 QList<Registration> registrations;
108 if (clientInfo.capabilities.workspace
109 && clientInfo.capabilities.workspace
110 ->value(u"didChangeWatchedFiles"_s)[u"dynamicRegistration"_s]
111 .toBool(false)) {
112 const int watchAll =
113 int(WatchKind::Create) | int(WatchKind::Change) | int(WatchKind::Delete);
114 DidChangeWatchedFilesRegistrationOptions watchedFilesParams;
115 FileSystemWatcher qmlWatcher;
116 qmlWatcher.globPattern = QByteArray("*.{qml,js,mjs}");
117 qmlWatcher.kind = watchAll;
118 FileSystemWatcher qmldirWatcher;
119 qmldirWatcher.globPattern = "qmldir";
120 qmldirWatcher.kind = watchAll;
121 FileSystemWatcher qmltypesWatcher;
122 qmltypesWatcher.globPattern = QByteArray("*.qmltypes");
123 qmltypesWatcher.kind = watchAll;
124 watchedFilesParams.watchers = QList<FileSystemWatcher>({
125 std::move(qmlWatcher),
126 std::move(qmldirWatcher),
127 std::move(qmltypesWatcher)
128 });
129 registrations.append(Registration {
130 // use ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles as id too
131 ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles,
132 ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles,
133 QTypedJson::toJsonValue(watchedFilesParams) });
134 }
135
136 if (!registrations.isEmpty()) {
137 RegistrationParams params;
138 params.registrations = registrations;
139 protocol->requestRegistration(
140 params,
141 []() {
142 // successful registration
143 },
144 [protocol](const ResponseError &err) {
145 LogMessageParams msg;
146 msg.message = QByteArray("Registration of file updates failed, will miss file "
147 "changes from outside the editor.");
148 msg.message.append(QString::number(err.code).toUtf8());
149 if (!err.message.isEmpty())
150 msg.message.append(" ");
151 msg.message.append(err.message);
152 msg.type = MessageType::Warning;
153 qCWarning(lspServerLog) << QString::fromUtf8(msg.message);
154 protocol->notifyLogMessage(msg);
155 });
156 }
157}
158
159QT_END_NAMESPACE
Implements a server for the language server protocol.
void setupCapabilities(const QLspSpecification::InitializeParams &clientInfo, QLspSpecification::InitializeResult &) override
void registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol) override