aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlls/qworkspace.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlls/qworkspace.cpp')
-rw-r--r--src/qmlls/qworkspace.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/qmlls/qworkspace.cpp b/src/qmlls/qworkspace.cpp
new file mode 100644
index 0000000000..ea8f2d6005
--- /dev/null
+++ b/src/qmlls/qworkspace.cpp
@@ -0,0 +1,172 @@
+// 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 "qworkspace_p.h"
+#include "qqmllanguageserver_p.h"
+#include "qqmllsutils_p.h"
+
+#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
+#include <QtLanguageServer/private/qlspnotifysignals_p.h>
+
+#include <QtCore/qfile.h>
+#include <variant>
+
+QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+using namespace QLspSpecification;
+
+void WorkspaceHandlers::registerHandlers(QLanguageServer *server, QLanguageServerProtocol *)
+{
+ QObject::connect(server->notifySignals(),
+ &QLspNotifySignals::receivedDidChangeWorkspaceFoldersNotification, this,
+ [server, this](const DidChangeWorkspaceFoldersParams &params) {
+ const WorkspaceFoldersChangeEvent &event = params.event;
+
+ const QList<WorkspaceFolder> &removed = event.removed;
+ QList<QByteArray> toRemove;
+ for (const WorkspaceFolder &folder : removed) {
+ toRemove.append(QQmlLSUtils::lspUriToQmlUrl(folder.uri));
+ m_codeModel->removeDirectory(m_codeModel->url2Path(
+ QQmlLSUtils::lspUriToQmlUrl(folder.uri)));
+ }
+ m_codeModel->removeRootUrls(toRemove);
+ const QList<WorkspaceFolder> &added = event.added;
+ QList<QByteArray> toAdd;
+ QStringList pathsToAdd;
+ for (const WorkspaceFolder &folder : added) {
+ toAdd.append(QQmlLSUtils::lspUriToQmlUrl(folder.uri));
+ pathsToAdd.append(m_codeModel->url2Path(
+ QQmlLSUtils::lspUriToQmlUrl(folder.uri)));
+ }
+ m_codeModel->addRootUrls(toAdd);
+ m_codeModel->addDirectoriesToIndex(pathsToAdd, server);
+ });
+
+ QObject::connect(server->notifySignals(),
+ &QLspNotifySignals::receivedDidChangeWatchedFilesNotification, this,
+ [this](const DidChangeWatchedFilesParams &params) {
+ const QList<FileEvent> &changes = params.changes;
+ for (const FileEvent &change : changes) {
+ const QString filename =
+ m_codeModel->url2Path(QQmlLSUtils::lspUriToQmlUrl(change.uri));
+ switch (FileChangeType(change.type)) {
+ case FileChangeType::Created:
+ // m_codeModel->addFile(filename);
+ break;
+ case FileChangeType::Changed: {
+ QFile file(filename);
+ if (file.open(QIODevice::ReadOnly))
+ // m_modelManager->setFileContents(filename, file.readAll());
+ break;
+ break;
+ }
+ case FileChangeType::Deleted:
+ // m_modelManager->removeFile(filename);
+ break;
+ }
+ }
+ // update due to dep changes...
+ });
+
+ QObject::connect(server, &QLanguageServer::clientInitialized, this,
+ &WorkspaceHandlers::clientInitialized);
+}
+
+QString WorkspaceHandlers::name() const
+{
+ return u"Workspace"_s;
+}
+
+void WorkspaceHandlers::setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
+ QLspSpecification::InitializeResult &serverInfo)
+{
+ if (!clientInfo.capabilities.workspace
+ || !clientInfo.capabilities.workspace->value(u"workspaceFolders"_s).toBool(false))
+ return;
+ WorkspaceFoldersServerCapabilities folders;
+ folders.supported = true;
+ folders.changeNotifications = true;
+ if (!serverInfo.capabilities.workspace)
+ serverInfo.capabilities.workspace = QJsonObject();
+ serverInfo.capabilities.workspace->insert(u"workspaceFolders"_s,
+ QTypedJson::toJsonValue(folders));
+}
+
+void WorkspaceHandlers::clientInitialized(QLanguageServer *server)
+{
+ QLanguageServerProtocol *protocol = server->protocol();
+ const auto clientInfo = server->clientInfo();
+ QList<Registration> registrations;
+ if (clientInfo.capabilities.workspace
+ && clientInfo.capabilities.workspace
+ ->value(u"didChangeWatchedFiles"_s)[u"dynamicRegistration"_s]
+ .toBool(false)) {
+ const int watchAll =
+ int(WatchKind::Create) | int(WatchKind::Change) | int(WatchKind::Delete);
+ DidChangeWatchedFilesRegistrationOptions watchedFilesParams;
+ FileSystemWatcher qmlWatcher;
+ qmlWatcher.globPattern = QByteArray("*.{qml,js,mjs}");
+ qmlWatcher.kind = watchAll;
+ FileSystemWatcher qmldirWatcher;
+ qmldirWatcher.globPattern = "qmldir";
+ qmldirWatcher.kind = watchAll;
+ FileSystemWatcher qmltypesWatcher;
+ qmltypesWatcher.globPattern = QByteArray("*.qmltypes");
+ qmltypesWatcher.kind = watchAll;
+ watchedFilesParams.watchers = QList<FileSystemWatcher>({
+ std::move(qmlWatcher),
+ std::move(qmldirWatcher),
+ std::move(qmltypesWatcher)
+ });
+ registrations.append(Registration {
+ // use ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles as id too
+ ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles,
+ ClientCapabilitiesInfo::WorkspaceDidChangeWatchedFiles,
+ QTypedJson::toJsonValue(watchedFilesParams) });
+ }
+
+ if (!registrations.isEmpty()) {
+ RegistrationParams params;
+ params.registrations = registrations;
+ protocol->requestRegistration(
+ params,
+ []() {
+ // successful registration
+ },
+ [protocol](const ResponseError &err) {
+ LogMessageParams msg;
+ msg.message = QByteArray("registration of file udates failed, will miss file "
+ "changes done outside the editor due to error ");
+ msg.message.append(QString::number(err.code).toUtf8());
+ if (!err.message.isEmpty())
+ msg.message.append(" ");
+ msg.message.append(err.message);
+ msg.type = MessageType::Warning;
+ qCWarning(lspServerLog) << QString::fromUtf8(msg.message);
+ protocol->notifyLogMessage(msg);
+ });
+ }
+
+ QSet<QString> rootPaths;
+ if (std::holds_alternative<QByteArray>(clientInfo.rootUri)) {
+ QString path = m_codeModel->url2Path(
+ QQmlLSUtils::lspUriToQmlUrl(std::get<QByteArray>(clientInfo.rootUri)));
+ rootPaths.insert(path);
+ } else if (clientInfo.rootPath && std::holds_alternative<QByteArray>(*clientInfo.rootPath)) {
+ QString path = QString::fromUtf8(std::get<QByteArray>(*clientInfo.rootPath));
+ rootPaths.insert(path);
+ }
+
+ if (clientInfo.workspaceFolders
+ && std::holds_alternative<QList<WorkspaceFolder>>(*clientInfo.workspaceFolders)) {
+ for (const WorkspaceFolder &workspace :
+ std::as_const(std::get<QList<WorkspaceFolder>>(*clientInfo.workspaceFolders))) {
+ const QUrl workspaceUrl(QString::fromUtf8(QQmlLSUtils::lspUriToQmlUrl(workspace.uri)));
+ rootPaths.insert(workspaceUrl.toLocalFile());
+ }
+ }
+ if (m_status == Status::Indexing)
+ m_codeModel->addDirectoriesToIndex(QStringList(rootPaths.begin(), rootPaths.end()), server);
+}
+
+QT_END_NAMESPACE