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 "qworkspace_p.h"
5#include "qqmllanguageserver_p.h"
6#include "qqmllsutils_p.h"
7
8#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
9#include <QtLanguageServer/private/qlspnotifysignals_p.h>
10
11#include <QtCore/qfile.h>
12#include <variant>
13
14QT_BEGIN_NAMESPACE
15using namespace Qt::StringLiterals;
16using namespace QLspSpecification;
17
18void WorkspaceHandlers::registerHandlers(QLanguageServer *server, QLanguageServerProtocol *)
19{
20 QObject::connect(sender: server->notifySignals(),
21 signal: &QLspNotifySignals::receivedDidChangeWorkspaceFoldersNotification, context: this,
22 slot: [server, this](const DidChangeWorkspaceFoldersParams &params) {
23 const WorkspaceFoldersChangeEvent &event = params.event;
24
25 const QList<WorkspaceFolder> &removed = event.removed;
26 QList<QByteArray> toRemove;
27 for (const WorkspaceFolder &folder : removed) {
28 toRemove.append(t: QQmlLSUtils::lspUriToQmlUrl(uri: folder.uri));
29 m_codeModel->removeDirectory(path: m_codeModel->url2Path(
30 url: QQmlLSUtils::lspUriToQmlUrl(uri: folder.uri)));
31 }
32 m_codeModel->removeRootUrls(urls: toRemove);
33 const QList<WorkspaceFolder> &added = event.added;
34 QList<QByteArray> toAdd;
35 QStringList pathsToAdd;
36 for (const WorkspaceFolder &folder : added) {
37 toAdd.append(t: QQmlLSUtils::lspUriToQmlUrl(uri: folder.uri));
38 pathsToAdd.append(t: m_codeModel->url2Path(
39 url: QQmlLSUtils::lspUriToQmlUrl(uri: folder.uri)));
40 }
41 m_codeModel->addRootUrls(urls: toAdd);
42 m_codeModel->addDirectoriesToIndex(paths: pathsToAdd, server);
43 });
44
45 QObject::connect(sender: server->notifySignals(),
46 signal: &QLspNotifySignals::receivedDidChangeWatchedFilesNotification, context: this,
47 slot: [this](const DidChangeWatchedFilesParams &params) {
48 const QList<FileEvent> &changes = params.changes;
49 for (const FileEvent &change : changes) {
50 const QString filename =
51 m_codeModel->url2Path(url: QQmlLSUtils::lspUriToQmlUrl(uri: change.uri));
52 switch (FileChangeType(change.type)) {
53 case FileChangeType::Created:
54 // m_codeModel->addFile(filename);
55 break;
56 case FileChangeType::Changed: {
57 QFile file(filename);
58 if (file.open(flags: QIODevice::ReadOnly))
59 // m_modelManager->setFileContents(filename, file.readAll());
60 break;
61 break;
62 }
63 case FileChangeType::Deleted:
64 // m_modelManager->removeFile(filename);
65 break;
66 }
67 }
68 // update due to dep changes...
69 });
70
71 QObject::connect(sender: server, signal: &QLanguageServer::clientInitialized, context: this,
72 slot: &WorkspaceHandlers::clientInitialized);
73}
74
75QString WorkspaceHandlers::name() const
76{
77 return u"Workspace"_s;
78}
79
80void WorkspaceHandlers::setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
81 QLspSpecification::InitializeResult &serverInfo)
82{
83 if (!clientInfo.capabilities.workspace
84 || !clientInfo.capabilities.workspace->value(key: u"workspaceFolders"_s).toBool(defaultValue: false))
85 return;
86 WorkspaceFoldersServerCapabilities folders;
87 folders.supported = true;
88 folders.changeNotifications = true;
89 if (!serverInfo.capabilities.workspace)
90 serverInfo.capabilities.workspace = QJsonObject();
91 serverInfo.capabilities.workspace->insert(key: u"workspaceFolders"_s,
92 value: QTypedJson::toJsonValue(params: folders));
93}
94
95void WorkspaceHandlers::clientInitialized(QLanguageServer *server)
96{
97 QLanguageServerProtocol *protocol = server->protocol();
98 const auto clientInfo = server->clientInfo();
99 QList<Registration> registrations;
100 if (clientInfo.capabilities.workspace
101 && clientInfo.capabilities.workspace
102 ->value(key: u"didChangeWatchedFiles"_s)[u"dynamicRegistration"_s]
103 .toBool(defaultValue: false)) {
104 const int watchAll =
105 int(WatchKind::Create) | int(WatchKind::Change) | int(WatchKind::Delete);
106 DidChangeWatchedFilesRegistrationOptions watchedFilesParams;
107 FileSystemWatcher qmlWatcher;
108 qmlWatcher.globPattern = QByteArray("*.{qml,js,mjs}");
109 qmlWatcher.kind = watchAll;
110 FileSystemWatcher qmldirWatcher;
111 qmldirWatcher.globPattern = "qmldir";
112 qmldirWatcher.kind = watchAll;
113 FileSystemWatcher qmltypesWatcher;
114 qmltypesWatcher.globPattern = QByteArray("*.qmltypes");
115 qmltypesWatcher.kind = watchAll;
116 watchedFilesParams.watchers = QList<FileSystemWatcher>({
117 std::move(qmlWatcher),
118 std::move(qmldirWatcher),
119 std::move(qmltypesWatcher)
120 });
121 registrations.append(t: Registration {
122 // use ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles as id too
123 .id: ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles,
124 .method: ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles,
125 .registerOptions: QTypedJson::toJsonValue(params: watchedFilesParams) });
126 }
127
128 if (!registrations.isEmpty()) {
129 RegistrationParams params;
130 params.registrations = registrations;
131 protocol->requestRegistration(
132 params,
133 responseHandler: []() {
134 // successful registration
135 },
136 errorHandler: [protocol](const ResponseError &err) {
137 LogMessageParams msg;
138 msg.message = QByteArray("registration of file udates failed, will miss file "
139 "changes done outside the editor due to error ");
140 msg.message.append(a: QString::number(err.code).toUtf8());
141 if (!err.message.isEmpty())
142 msg.message.append(s: " ");
143 msg.message.append(a: err.message);
144 msg.type = MessageType::Warning;
145 qCWarning(lspServerLog) << QString::fromUtf8(ba: msg.message);
146 protocol->notifyLogMessage(params: msg);
147 });
148 }
149
150 QSet<QString> rootPaths;
151 if (std::holds_alternative<QByteArray>(v: clientInfo.rootUri)) {
152 QString path = m_codeModel->url2Path(
153 url: QQmlLSUtils::lspUriToQmlUrl(uri: std::get<QByteArray>(v: clientInfo.rootUri)));
154 rootPaths.insert(value: path);
155 } else if (clientInfo.rootPath && std::holds_alternative<QByteArray>(v: *clientInfo.rootPath)) {
156 QString path = QString::fromUtf8(ba: std::get<QByteArray>(v: *clientInfo.rootPath));
157 rootPaths.insert(value: path);
158 }
159
160 if (clientInfo.workspaceFolders
161 && std::holds_alternative<QList<WorkspaceFolder>>(v: *clientInfo.workspaceFolders)) {
162 for (const WorkspaceFolder &workspace :
163 std::as_const(t: std::get<QList<WorkspaceFolder>>(v: *clientInfo.workspaceFolders))) {
164 const QUrl workspaceUrl(QString::fromUtf8(ba: QQmlLSUtils::lspUriToQmlUrl(uri: workspace.uri)));
165 rootPaths.insert(value: workspaceUrl.toLocalFile());
166 }
167 }
168 if (m_status == Status::Indexing)
169 m_codeModel->addDirectoriesToIndex(paths: QStringList(rootPaths.begin(), rootPaths.end()), server);
170}
171
172QT_END_NAMESPACE
173

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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