| 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 "qtextsynchronization_p.h" | 
| 5 | #include "qqmllsutils_p.h" | 
| 6 | #include "qtextdocument_p.h" | 
| 7 |  | 
| 8 | using namespace QLspSpecification; | 
| 9 | using namespace Qt::StringLiterals; | 
| 10 |  | 
| 11 | QT_BEGIN_NAMESPACE | 
| 12 |  | 
| 13 | TextSynchronization::TextSynchronization(QmlLsp::QQmlCodeModel *codeModel, QObject *parent) | 
| 14 |     : QLanguageServerModule(parent), m_codeModel(codeModel) | 
| 15 | { | 
| 16 | } | 
| 17 |  | 
| 18 | void TextSynchronization::didCloseTextDocument(const DidCloseTextDocumentParams ¶ms) | 
| 19 | { | 
| 20 |     m_codeModel->closeOpenFile(url: QQmlLSUtils::lspUriToQmlUrl(uri: params.textDocument.uri)); | 
| 21 | } | 
| 22 |  | 
| 23 | void TextSynchronization::didOpenTextDocument(const DidOpenTextDocumentParams ¶ms) | 
| 24 | { | 
| 25 |     const TextDocumentItem &item = params.textDocument; | 
| 26 |     const QString fileName = m_codeModel->url2Path(url: QQmlLSUtils::lspUriToQmlUrl(uri: item.uri)); | 
| 27 |     m_codeModel->newOpenFile(url: QQmlLSUtils::lspUriToQmlUrl(uri: item.uri), version: item.version, | 
| 28 |                              docText: QString::fromUtf8(ba: item.text)); | 
| 29 | } | 
| 30 |  | 
| 31 | void TextSynchronization::didDidChangeTextDocument(const DidChangeTextDocumentParams ¶ms) | 
| 32 | { | 
| 33 |     QByteArray url = QQmlLSUtils::lspUriToQmlUrl(uri: params.textDocument.uri); | 
| 34 |     const QString fileName = m_codeModel->url2Path(url); | 
| 35 |     auto openDoc = m_codeModel->openDocumentByUrl(url); | 
| 36 |     std::shared_ptr<Utils::TextDocument> document = openDoc.textDocument; | 
| 37 |     if (!document) { | 
| 38 |         qCWarning(lspServerLog) << "Ingnoring changes to non open or closed document"  | 
| 39 |                                 << QString::fromUtf8(ba: url); | 
| 40 |         return; | 
| 41 |     } | 
| 42 |     const auto &changes = params.contentChanges; | 
| 43 |     { | 
| 44 |         QMutexLocker l(document->mutex()); | 
| 45 |         for (const auto &change : changes) { | 
| 46 |             if (!change.range) { | 
| 47 |                 document->setPlainText(QString::fromUtf8(ba: change.text)); | 
| 48 |                 continue; | 
| 49 |             } | 
| 50 |  | 
| 51 |             const auto &range = *change.range; | 
| 52 |             const auto &rangeStart = range.start; | 
| 53 |             const int start = | 
| 54 |                     document->findBlockByNumber(blockNumber: rangeStart.line).position() + rangeStart.character; | 
| 55 |             const auto &rangeEnd = range.end; | 
| 56 |             const int end = | 
| 57 |                     document->findBlockByNumber(blockNumber: rangeEnd.line).position() + rangeEnd.character; | 
| 58 |  | 
| 59 |             document->setPlainText(document->toPlainText().replace(i: start, len: end - start, | 
| 60 |                                                                    after: QString::fromUtf8(ba: change.text))); | 
| 61 |         } | 
| 62 |         document->setVersion(params.textDocument.version); | 
| 63 |         qCDebug(lspServerLog).noquote() | 
| 64 |                 << "text is\n:----------"  << document->toPlainText() << "\n_________" ; | 
| 65 |     } | 
| 66 |     m_codeModel->addOpenToUpdate(url); | 
| 67 |     m_codeModel->openNeedUpdate(); | 
| 68 | } | 
| 69 |  | 
| 70 | void TextSynchronization::registerHandlers(QLanguageServer *server, QLanguageServerProtocol *) | 
| 71 | { | 
| 72 |     QObject::connect(sender: server->notifySignals(), | 
| 73 |                      signal: &QLspNotifySignals::receivedDidOpenTextDocumentNotification, context: this, | 
| 74 |                      slot: &TextSynchronization::didOpenTextDocument); | 
| 75 |  | 
| 76 |     QObject::connect(sender: server->notifySignals(), | 
| 77 |                      signal: &QLspNotifySignals::receivedDidChangeTextDocumentNotification, context: this, | 
| 78 |                      slot: &TextSynchronization::didDidChangeTextDocument); | 
| 79 |  | 
| 80 |     QObject::connect(sender: server->notifySignals(), | 
| 81 |                      signal: &QLspNotifySignals::receivedDidCloseTextDocumentNotification, context: this, | 
| 82 |                      slot: &TextSynchronization::didCloseTextDocument); | 
| 83 | } | 
| 84 |  | 
| 85 | QString TextSynchronization::name() const | 
| 86 | { | 
| 87 |     return u"TextSynchonization"_s ; | 
| 88 | } | 
| 89 |  | 
| 90 | void TextSynchronization::setupCapabilities(const QLspSpecification::InitializeParams &, | 
| 91 |                                             QLspSpecification::InitializeResult &serverInfo) | 
| 92 | { | 
| 93 |     TextDocumentSyncOptions syncOptions; | 
| 94 |     syncOptions.openClose = true; | 
| 95 |     syncOptions.change = TextDocumentSyncKind::Incremental; | 
| 96 |     serverInfo.capabilities.textDocumentSync = syncOptions; | 
| 97 | } | 
| 98 |  | 
| 99 | QT_END_NAMESPACE | 
| 100 |  |