diff --git a/tools/qmlls/qmllintsuggestions.cpp b/tools/qmlls/qmllintsuggestions.cpp index 75ada742b7..2d53c29c19 100644 --- a/tools/qmlls/qmllintsuggestions.cpp +++ b/tools/qmlls/qmllintsuggestions.cpp @@ -123,19 +123,19 @@ QmlLintSuggestions::QmlLintSuggestions(QLanguageServer *server, QmlLsp::QQmlCode &QmlLintSuggestions::diagnose, Qt::DirectConnection); } -void QmlLintSuggestions::diagnose(const QByteArray &uri) +void QmlLintSuggestions::diagnose(const QByteArray &url) { const int maxInvalidMsec = 4000; qCDebug(lintLog) << "diagnose start"; - QmlLsp::OpenDocumentSnapshot snapshot = m_codeModel->snapshotByUri(uri); + QmlLsp::OpenDocumentSnapshot snapshot = m_codeModel->snapshotByUrl(url); QList diagnostics; std::optional version; DomItem doc; { QMutexLocker l(&m_mutex); - LastLintUpdate &lastUpdate = m_lastUpdate[uri]; + LastLintUpdate &lastUpdate = m_lastUpdate[url]; if (lastUpdate.version && *lastUpdate.version == version) { - qCDebug(lspServerLog) << "skipped update of " << uri << "unchanged valid doc"; + qCDebug(lspServerLog) << "skipped update of " << url << "unchanged valid doc"; return; } if (snapshot.validDocVersion @@ -153,7 +153,7 @@ void QmlLintSuggestions::diagnose(const QByteArray &uri) } else if (!lastUpdate.invalidUpdatesSince) { lastUpdate.invalidUpdatesSince = QDateTime::currentDateTime(); QTimer::singleShot(maxInvalidMsec, Qt::VeryCoarseTimer, this, - [this, uri]() { diagnose(uri); }); + [this, url]() { diagnose(url); }); } } if (doc) { @@ -273,12 +273,12 @@ void QmlLintSuggestions::diagnose(const QByteArray &uri) } } PublishDiagnosticsParams diagnosticParams; - diagnosticParams.uri = uri; + diagnosticParams.uri = url; diagnosticParams.diagnostics = diagnostics; diagnosticParams.version = version; m_server->protocol()->notifyPublishDiagnostics(diagnosticParams); - qCDebug(lintLog) << "lint" << QString::fromUtf8(uri) << "found" + qCDebug(lintLog) << "lint" << QString::fromUtf8(url) << "found" << diagnosticParams.diagnostics.size() << "issues" << QTypedJson::toJsonValue(diagnosticParams); } diff --git a/tools/qmlls/qqmlcodemodel.cpp b/tools/qmlls/qqmlcodemodel.cpp index 01a1719094..b1dfd17718 100644 --- a/tools/qmlls/qqmlcodemodel.cpp +++ b/tools/qmlls/qqmlcodemodel.cpp @@ -64,11 +64,11 @@ synchronization here. \section2 OpenFiles \list -\li snapshotByUri() returns an OpenDocumentSnapshot of an open document. From it you can get the +\li snapshotByUrl() returns an OpenDocumentSnapshot of an open document. From it you can get the document, its latest valid version, scope, all connected to a specific version of the document and immutable. The signal updatedSnapshot() is called every time a snapshot changes (also for every partial change: document change, validDocument change, scope change). -\li openDocumentByUri() is a lower level and more intrusive access to OpenDocument objects. These +\li openDocumentByUrl() is a lower level and more intrusive access to OpenDocument objects. These contains the current snapshot, and shared pointer to a Utils::TextDocument. This is *always* the current version of the document, and has line by line support. Working on it is more delicate and intrusive, because you have to explicitly acquire its mutex() @@ -124,9 +124,9 @@ QQmlCodeModel::~QQmlCodeModel() } } -OpenDocumentSnapshot QQmlCodeModel::snapshotByUri(const QByteArray &uri) +OpenDocumentSnapshot QQmlCodeModel::snapshotByUrl(const QByteArray &url) { - return openDocumentByUri(uri).snapshot; + return openDocumentByUrl(url).snapshot; } int QQmlCodeModel::indexEvalProgress() const @@ -272,49 +272,49 @@ void QQmlCodeModel::removeDirectory(const QString &path) currentEnvPtr->removePath(path); } -QString QQmlCodeModel::uri2Path(const QByteArray &uri, UriLookup options) +QString QQmlCodeModel::url2Path(const QByteArray &url, UrlLookup options) { QString res; { QMutexLocker l(&m_mutex); - res = m_uri2path.value(uri); + res = m_url2path.value(url); } - if (!res.isEmpty() && options == UriLookup::Caching) + if (!res.isEmpty() && options == UrlLookup::Caching) return res; - QUrl url(QString::fromUtf8(uri)); - QFileInfo f(url.toLocalFile()); + QUrl qurl(QString::fromUtf8(url)); + QFileInfo f(qurl.toLocalFile()); QString cPath = f.canonicalFilePath(); if (cPath.isEmpty()) cPath = f.filePath(); { QMutexLocker l(&m_mutex); if (!res.isEmpty() && res != cPath) - m_path2uri.remove(res); - m_uri2path.insert(uri, cPath); - m_path2uri.insert(cPath, uri); + m_path2url.remove(res); + m_url2path.insert(url, cPath); + m_path2url.insert(cPath, url); } return cPath; } -void QQmlCodeModel::newOpenFile(const QByteArray &uri, int version, const QString &docText) +void QQmlCodeModel::newOpenFile(const QByteArray &url, int version, const QString &docText) { { QMutexLocker l(&m_mutex); - auto &openDoc = m_openDocuments[uri]; + auto &openDoc = m_openDocuments[url]; if (!openDoc.textDocument) openDoc.textDocument = std::make_shared(); QMutexLocker l2(openDoc.textDocument->mutex()); openDoc.textDocument->setVersion(version); openDoc.textDocument->setPlainText(docText); } - addOpenToUpdate(uri); + addOpenToUpdate(url); openNeedUpdate(); } -OpenDocument QQmlCodeModel::openDocumentByUri(const QByteArray &uri) +OpenDocument QQmlCodeModel::openDocumentByUrl(const QByteArray &url) { QMutexLocker l(&m_mutex); - return m_openDocuments.value(uri); + return m_openDocuments.value(url); } void QQmlCodeModel::indexNeedsUpdate() @@ -426,12 +426,12 @@ void QQmlCodeModel::openUpdateEnd() qCDebug(codeModelLog) << "openUpdateEnd"; } -void QQmlCodeModel::newDocForOpenFile(const QByteArray &uri, int version, const QString &docText) +void QQmlCodeModel::newDocForOpenFile(const QByteArray &url, int version, const QString &docText) { - qCDebug(codeModelLog) << "updating doc" << uri << "to version" << version << "(" + qCDebug(codeModelLog) << "updating doc" << url << "to version" << version << "(" << docText.length() << "chars)"; DomItem newCurrent = m_currentEnv.makeCopy(DomItem::CopyOption::EnvConnected).item(); - QString fPath = uri2Path(uri, UriLookup::ForceLookup); + QString fPath = url2Path(url, UrlLookup::ForceLookup); Path p; newCurrent.loadFile( fPath, fPath, docText, QDateTime::currentDateTimeUtc(), @@ -443,17 +443,17 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &uri, int version, const DomItem item = m_currentEnv.path(p); { QMutexLocker l(&m_mutex); - OpenDocument &doc = m_openDocuments[uri]; + OpenDocument &doc = m_openDocuments[url]; if (!doc.textDocument) { qCWarning(lspServerLog) - << "ignoring update to closed document" << QString::fromUtf8(uri); + << "ignoring update to closed document" << QString::fromUtf8(url); return; } else { QMutexLocker l(doc.textDocument->mutex()); if (doc.textDocument->version() && *doc.textDocument->version() > version) { qCWarning(lspServerLog) << "docUpdate: version" << version << "of document" - << QString::fromUtf8(uri) << "is not the latest anymore"; + << QString::fromUtf8(url) << "is not the latest anymore"; return; } } @@ -461,8 +461,8 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &uri, int version, const doc.snapshot.docVersion = version; doc.snapshot.doc = item; } else { - qCWarning(lspServerLog) << "skippig update of current doc to obsolete version" - << version << "of document" << QString::fromUtf8(uri); + qCWarning(lspServerLog) << "skipping update of current doc to obsolete version" + << version << "of document" << QString::fromUtf8(url); } if (item.field(Fields::isValid).value().toBool(false)) { if (!doc.snapshot.validDocVersion || *doc.snapshot.validDocVersion < version) { @@ -471,31 +471,31 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &uri, int version, const doc.snapshot.validDoc = vDoc; } else { qCWarning(lspServerLog) << "skippig update of valid doc to obsolete version" - << version << "of document" << QString::fromUtf8(uri); + << version << "of document" << QString::fromUtf8(url); } } else { qCWarning(lspServerLog) << "avoid update of validDoc to " << version << "of document" - << QString::fromUtf8(uri) << "as it is invalid"; + << QString::fromUtf8(url) << "as it is invalid"; } } } if (codeModelLog().isDebugEnabled()) { - qCDebug(codeModelLog) << "finished update doc of " << uri << "to version" << version; - snapshotByUri(uri).dump(qDebug() << "postSnapshot", + qCDebug(codeModelLog) << "finished update doc of " << url << "to version" << version; + snapshotByUrl(url).dump(qDebug() << "postSnapshot", OpenDocumentSnapshot::DumpOption::AllCode); } - // we should update the scope in the future thus call addOpen(uri) - emit updatedSnapshot(uri); + // we should update the scope in the future thus call addOpen(url) + emit updatedSnapshot(url); } -void QQmlCodeModel::closeOpenFile(const QByteArray &uri) +void QQmlCodeModel::closeOpenFile(const QByteArray &url) { QMutexLocker l(&m_mutex); - m_openDocuments.remove(uri); + m_openDocuments.remove(url); } -void QQmlCodeModel::openUpdate(const QByteArray &uri) +void QQmlCodeModel::openUpdate(const QByteArray &url) { bool updateDoc = false; bool updateScope = false; @@ -505,7 +505,7 @@ void QQmlCodeModel::openUpdate(const QByteArray &uri) std::shared_ptr document; { QMutexLocker l(&m_mutex); - OpenDocument &doc = m_openDocuments[uri]; + OpenDocument &doc = m_openDocuments[url]; document = doc.textDocument; if (!document) return; @@ -531,23 +531,23 @@ void QQmlCodeModel::openUpdate(const QByteArray &uri) } } if (updateDoc) { - newDocForOpenFile(uri, *rNow, docText); + newDocForOpenFile(url, *rNow, docText); } if (updateScope) { // to do } } -void QQmlCodeModel::addOpenToUpdate(const QByteArray &uri) +void QQmlCodeModel::addOpenToUpdate(const QByteArray &url) { QMutexLocker l(&m_mutex); - m_openDocumentsToUpdate.insert(uri); + m_openDocumentsToUpdate.insert(url); } QDebug OpenDocumentSnapshot::dump(QDebug dbg, DumpOptions options) { dbg.noquote().nospace() << "{"; - dbg << " uri:" << QString::fromUtf8(uri) << "\n"; + dbg << " url:" << QString::fromUtf8(url) << "\n"; dbg << " docVersion:" << (docVersion ? QString::number(*docVersion) : u"*none*"_s) << "\n"; if (options & DumpOption::LatestCode) { dbg << " doc: ------------\n" diff --git a/tools/qmlls/qqmlcodemodel.h b/tools/qmlls/qqmlcodemodel.h index cf7a3cacbe..c217ef8437 100644 --- a/tools/qmlls/qqmlcodemodel.h +++ b/tools/qmlls/qqmlcodemodel.h @@ -52,7 +52,7 @@ public: AllCode = LatestCode | ValidCode }; Q_DECLARE_FLAGS(DumpOptions, DumpOption) - QByteArray uri; + QByteArray url; std::optional docVersion; QQmlJS::Dom::DomItem doc; std::optional validDocVersion; @@ -83,15 +83,15 @@ class QQmlCodeModel : public QObject { Q_OBJECT public: - enum class UriLookup { Caching, ForceLookup }; + enum class UrlLookup { Caching, ForceLookup }; enum class State { Running, Stopping }; explicit QQmlCodeModel(QObject *parent = nullptr); ~QQmlCodeModel(); QQmlJS::Dom::DomItem currentEnv(); QQmlJS::Dom::DomItem validEnv(); - OpenDocumentSnapshot snapshotByUri(const QByteArray &uri); - OpenDocument openDocumentByUri(const QByteArray &uri); + OpenDocumentSnapshot snapshotByUrl(const QByteArray &url); + OpenDocument openDocumentByUrl(const QByteArray &url); void openNeedUpdate(); void indexNeedsUpdate(); @@ -99,12 +99,12 @@ public: void addOpenToUpdate(const QByteArray &); void removeDirectory(const QString &path); // void updateDocument(const OpenDocument &doc); - QString uri2Path(const QByteArray &uri, UriLookup options = UriLookup::Caching); - void newOpenFile(const QByteArray &uri, int version, const QString &docText); - void newDocForOpenFile(const QByteArray &uri, int version, const QString &docText); - void closeOpenFile(const QByteArray &uri); + QString url2Path(const QByteArray &url, UrlLookup options = UrlLookup::Caching); + void newOpenFile(const QByteArray &url, int version, const QString &docText); + void newDocForOpenFile(const QByteArray &url, int version, const QString &docText); + void closeOpenFile(const QByteArray &url); signals: - void updatedSnapshot(const QByteArray &uri); + void updatedSnapshot(const QByteArray &url); private: void indexDirectory(const QString &path, int depthLeft); int indexEvalProgress() const; // to be called in the mutex @@ -130,8 +130,8 @@ private: QQmlJS::Dom::DomItem m_validEnv; QByteArray m_lastOpenDocumentUpdated; QSet m_openDocumentsToUpdate; - QHash m_uri2path; - QHash m_path2uri; + QHash m_url2path; + QHash m_path2url; QHash m_openDocuments; }; diff --git a/tools/qmlls/qqmllanguageserver.h b/tools/qmlls/qqmllanguageserver.h index 67f002fee3..ea445c8e85 100644 --- a/tools/qmlls/qqmllanguageserver.h +++ b/tools/qmlls/qqmllanguageserver.h @@ -36,6 +36,19 @@ QT_BEGIN_NAMESPACE namespace QmlLsp { +/* + * The language server protocol calls "URI" what QML calls "URL". + * According to RFC 3986, a URL is a special case of URI that not only + * identifies a resource but also shows how to access it. + * In QML, however, URIs are distinct from URLs. URIs are the + * identifiers of modules, for example "QtQuick.Controls". + * In order to not confuse the terms we interpret language server URIs + * as URLs in the QML code model. + * This method marks a point of translation between the terms, but does + * not have to change the actual URI/URL. + */ +inline QByteArray lspUriToQmlUrl(const QByteArray &uri) { return uri; } + class QQmlLanguageServer : public QLanguageServerModule { Q_OBJECT diff --git a/tools/qmlls/textsynchronization.cpp b/tools/qmlls/textsynchronization.cpp index efd06aea98..70da3ee964 100644 --- a/tools/qmlls/textsynchronization.cpp +++ b/tools/qmlls/textsynchronization.cpp @@ -42,26 +42,25 @@ TextSynchronization::TextSynchronization(QmlLsp::QQmlCodeModel *codeModel, QObje void TextSynchronization::didCloseTextDocument(const DidCloseTextDocumentParams ¶ms) { - m_codeModel->closeOpenFile(params.textDocument.uri); + m_codeModel->closeOpenFile(QmlLsp::lspUriToQmlUrl(params.textDocument.uri)); } void TextSynchronization::didOpenTextDocument(const DidOpenTextDocumentParams ¶ms) { const TextDocumentItem &item = params.textDocument; - const QString fileName = m_codeModel->uri2Path(item.uri); - - m_codeModel->newOpenFile(item.uri, item.version, item.text); + const QString fileName = m_codeModel->url2Path(QmlLsp::lspUriToQmlUrl(item.uri)); + m_codeModel->newOpenFile(QmlLsp::lspUriToQmlUrl(item.uri), item.version, item.text); } void TextSynchronization::didDidChangeTextDocument(const DidChangeTextDocumentParams ¶ms) { - QByteArray uri = params.textDocument.uri; - const QString fileName = m_codeModel->uri2Path(uri); - auto openDoc = m_codeModel->openDocumentByUri(uri); + QByteArray url = QmlLsp::lspUriToQmlUrl(params.textDocument.uri); + const QString fileName = m_codeModel->url2Path(url); + auto openDoc = m_codeModel->openDocumentByUrl(url); std::shared_ptr document = openDoc.textDocument; if (!document) { qCWarning(lspServerLog) << "Ingnoring changes to non open or closed document" - << QString::fromUtf8(uri); + << QString::fromUtf8(url); return; } const auto &changes = params.contentChanges; @@ -86,7 +85,7 @@ void TextSynchronization::didDidChangeTextDocument(const DidChangeTextDocumentPa } document->setVersion(params.textDocument.version); } - m_codeModel->addOpenToUpdate(uri); + m_codeModel->addOpenToUpdate(url); m_codeModel->openNeedUpdate(); }