diff options
| author | Sami Shalayel <sami.shalayel@qt.io> | 2024-08-26 16:59:42 +0200 |
|---|---|---|
| committer | Sami Shalayel <sami.shalayel@qt.io> | 2024-09-10 12:01:33 +0200 |
| commit | 36a447a4112d3ed8f1588f8ddd17fe521aeee494 (patch) | |
| tree | c97df2212f3fe1ddf4691af5379eb17d45354e8e /src/qmlcompiler/qqmljsutils.cpp | |
| parent | b1ff6073a7247c921e20cd98b2e3297e7368681b (diff) | |
add util to map .qml from source to build folder
Add a helper method qmlSourcePathFromBuildPath in the QQmlJSUtils static
class that maps QML files from the build folder to their source folder,
and vice-versa.
Uses a heuristic for QML modules that do not use "prefer" qmldirs for
each folder that contains QML files.
It will be used in a later commit to translate build folder paths,
encountered during "go to definiton" in qmlls, to source folder paths.
Pick-to: 6.8 6.7
Task-number: QTBUG-127661
Change-Id: I81f4b75a008d773835affb622af7f964b753e5ac
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
Diffstat (limited to 'src/qmlcompiler/qqmljsutils.cpp')
| -rw-r--r-- | src/qmlcompiler/qqmljsutils.cpp | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/qmlcompiler/qqmljsutils.cpp b/src/qmlcompiler/qqmljsutils.cpp index fcf56d4b96..f40d4932ca 100644 --- a/src/qmlcompiler/qqmljsutils.cpp +++ b/src/qmlcompiler/qqmljsutils.cpp @@ -280,5 +280,98 @@ QStringList QQmlJSUtils::resourceFilesFromBuildFolders(const QStringList &buildF return result; } +enum FilterType { + LocalFileFilter, + ResourceFileFilter +}; + +/*! +\internal +Obtain a QML module qrc entry from its qmldir entry. + +Contains a heuristic for QML modules without nested-qml-module-with-prefer-feature +that tries to find a parent directory that contains a qmldir entry in the qrc. +*/ +static QQmlJSResourceFileMapper::Entry +qmlModuleEntryFromBuildPath(const QQmlJSResourceFileMapper *mapper, + const QString &pathInBuildFolder, FilterType type) +{ + const QString cleanPath = QDir::cleanPath(pathInBuildFolder); + QStringView directoryPath = cleanPath; + + while (!directoryPath.isEmpty()) { + const qsizetype lastSlashIndex = directoryPath.lastIndexOf(u'/'); + if (lastSlashIndex == -1) + return {}; + + directoryPath.truncate(lastSlashIndex); + const QString qmldirPath = u"%1/qmldir"_s.arg(directoryPath); + const QQmlJSResourceFileMapper::Filter qmldirFilter = type == LocalFileFilter + ? QQmlJSResourceFileMapper::localFileFilter(qmldirPath) + : QQmlJSResourceFileMapper::resourceFileFilter(qmldirPath); + + QQmlJSResourceFileMapper::Entry result = mapper->entry(qmldirFilter); + if (result.isValid()) { + result.resourcePath.chop(std::char_traits<char>::length("/qmldir")); + result.filePath.chop(std::char_traits<char>::length("/qmldir")); + return result; + } + } + return {}; +} + +/*! +\internal +Obtains the source folder path from a build folder QML file path via the passed \c mapper. + +This works on proper QML modules when using the nested-qml-module-with-prefer-feature +from 6.8 and uses a heuristic when the qmldir with the prefer entry is missing. +*/ +QString QQmlJSUtils::qmlSourcePathFromBuildPath(const QQmlJSResourceFileMapper *mapper, + const QString &pathInBuildFolder) +{ + if (!mapper) + return pathInBuildFolder; + + const auto qmlModuleEntry = + qmlModuleEntryFromBuildPath(mapper, pathInBuildFolder, LocalFileFilter); + if (!qmlModuleEntry.isValid()) + return pathInBuildFolder; + const QString qrcPath = qmlModuleEntry.resourcePath + + QStringView(pathInBuildFolder).sliced(qmlModuleEntry.filePath.size()); + + const auto entry = mapper->entry(QQmlJSResourceFileMapper::resourceFileFilter(qrcPath)); + return entry.isValid()? entry.filePath : pathInBuildFolder; +} + +/*! +\internal +Obtains the source folder path from a build folder QML file path via the passed \c mapper, see also +\l QQmlJSUtils::qmlSourcePathFromBuildPath. +*/ +QString QQmlJSUtils::qmlBuildPathFromSourcePath(const QQmlJSResourceFileMapper *mapper, + const QString &pathInSourceFolder) +{ + if (!mapper) + return pathInSourceFolder; + + const QString qrcPath = + mapper->entry(QQmlJSResourceFileMapper::localFileFilter(pathInSourceFolder)) + .resourcePath; + + if (qrcPath.isEmpty()) + return pathInSourceFolder; + + const auto moduleBuildEntry = + qmlModuleEntryFromBuildPath(mapper, qrcPath, ResourceFileFilter); + + if (!moduleBuildEntry.isValid()) + return pathInSourceFolder; + + const auto qrcFolderPath = qrcPath.first(qrcPath.lastIndexOf(u'/')); // drop the filename + + return moduleBuildEntry.filePath + qrcFolderPath.sliced(moduleBuildEntry.resourcePath.size()) + + pathInSourceFolder.sliced(pathInSourceFolder.lastIndexOf(u'/')); +} QT_END_NAMESPACE |
