Revision control
++ // 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
++ // Qt-Security score:significant reason:default
++
++ #include "qqmlcodemodelmanager_p.h"
++ #include "qtextsynchronization_p.h"
++ #include "qqmllsutils_p.h"
++ #include "qtextdocument_p.h"
++
++ using namespace QLspSpecification;
++ using namespace Qt::StringLiterals;
++
++ QT_BEGIN_NAMESPACE
++
++ TextSynchronization::TextSynchronization(QmlLsp::QQmlCodeModelManager *codeModelManager,
++ QObject *parent)
++ : QLanguageServerModule(parent), m_codeModelManager(codeModelManager)
++ {
++ }
++
++ void TextSynchronization::didCloseTextDocument(const DidCloseTextDocumentParams ¶ms)
++ {
++ m_codeModelManager->closeOpenFile(QQmlLSUtils::lspUriToQmlUrl(params.textDocument.uri));
++ }
++
++ void TextSynchronization::didOpenTextDocument(const DidOpenTextDocumentParams ¶ms)
++ {
++ const TextDocumentItem &item = params.textDocument;
++ m_codeModelManager->newOpenFile(QQmlLSUtils::lspUriToQmlUrl(item.uri), item.version,
++ QString::fromUtf8(item.text));
++ }
++
++ void TextSynchronization::didDidChangeTextDocument(const DidChangeTextDocumentParams ¶ms)
++ {
++ QByteArray url = QQmlLSUtils::lspUriToQmlUrl(params.textDocument.uri);
++ auto openDoc = m_codeModelManager->openDocumentByUrl(url);
++ std::shared_ptr<Utils::TextDocument> document = openDoc.textDocument;
++ if (!document) {
++ qCWarning(lspServerLog) << "Ignoring changes to non open or closed document"
++ << QString::fromUtf8(url);
++ return;
++ }
++ const auto &changes = params.contentChanges;
++ {
++ QMutexLocker l(document->mutex());
++ for (const auto &change : changes) {
++ if (auto plainText = std::get_if<TextDocumentContentChangeWholeDocument>(&change)) {
++ document->setPlainText(QString::fromUtf8(plainText->text));
++ continue;
++ }
++
++ const auto &withRange = std::get<TextDocumentContentChangePartial>(change);
++ const auto &range = withRange.range;
++ const auto &rangeStart = range.start;
++ const int start =
++ document->findBlockByNumber(rangeStart.line).position() + rangeStart.character;
++ const auto &rangeEnd = range.end;
++ const int end =
++ document->findBlockByNumber(rangeEnd.line).position() + rangeEnd.character;
++
++ document->setPlainText(document->toPlainText().replace(
++ start, end - start, QString::fromUtf8(withRange.text)));
++ }
++ document->setVersion(params.textDocument.version);
++ qCDebug(lspServerLog).noquote()
++ << "text is\n:----------" << document->toPlainText() << "\n_________";
++ }
++ m_codeModelManager->addOpenToUpdate(url);
++ }
++
++ void TextSynchronization::registerHandlers(QLanguageServer *server, QLanguageServerProtocol *)
++ {
++ QObject::connect(server->notifySignals(),
++ &QLspNotifySignals::receivedDidOpenTextDocumentNotification, this,
++ &TextSynchronization::didOpenTextDocument);
++
++ QObject::connect(server->notifySignals(),
++ &QLspNotifySignals::receivedDidChangeTextDocumentNotification, this,
++ &TextSynchronization::didDidChangeTextDocument);
++
++ QObject::connect(server->notifySignals(),
++ &QLspNotifySignals::receivedDidCloseTextDocumentNotification, this,
++ &TextSynchronization::didCloseTextDocument);
++ }
++
++ void TextSynchronization::setupCapabilities(QLspSpecification::ServerCapabilities &caps)
++ {
++ TextDocumentSyncOptions syncOptions;
++ syncOptions.openClose = true;
++ syncOptions.change = TextDocumentSyncKind::Incremental;
++ caps.textDocumentSync = syncOptions;
++ }
++
++ QT_END_NAMESPACE