diff options
author | Alexander Mishin <apmishin@yandex.com> | 2020-09-21 19:39:24 +0300 |
---|---|---|
committer | Alexander Mishin <apmishin@yandex.com> | 2020-09-22 13:43:21 +0000 |
commit | 229dfaab95325ce64e27fe4503c8b99e5ec90bff (patch) | |
tree | 92ec0053afb057944ae96f84d0b652cde8410aee /src/plugins/python/pythonproject.cpp | |
parent | 31ec38dba5efb731b0769a2d3e4d0232d9ba6e22 (diff) | |
download | qt-creator-229dfaab95325ce64e27fe4503c8b99e5ec90bff.tar.gz |
Add qmlImportPaths property to .pyproject file
Users should be able to add custom QML import paths for
Python/PySide2/PyQt5 projects in Qt Creator in order to
get syntax highlighting and code completion for custom
QML modules.
Fixes: QTCREATORBUG-23679
Change-Id: Iec7c691c4b8709c48a790cd27ac7c6e755967796
Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins/python/pythonproject.cpp')
-rw-r--r-- | src/plugins/python/pythonproject.cpp | 119 |
1 files changed, 84 insertions, 35 deletions
diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 3b53292d8c..319fe245d6 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -46,6 +46,8 @@ #include <coreplugin/icore.h> #include <coreplugin/messagemanager.h> +#include <qmljs/qmljsmodelmanagerinterface.h> + #include <utils/fileutils.h> using namespace Core; @@ -80,10 +82,12 @@ public: private: QStringList m_rawFileList; QStringList m_files; + QStringList m_rawQmlImportPathList; + QStringList m_qmlImportPaths; QHash<QString, QString> m_rawListEntries; + QHash<QString, QString> m_rawQmlImportPathEntries; }; - /** * @brief Provides displayName relative to project node */ @@ -101,6 +105,38 @@ private: QString m_displayName; }; +static QJsonObject readObjJson(const FilePath &projectFile, QString *errorMessage) +{ + QFile file(projectFile.toString()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + *errorMessage = PythonProject::tr("Unable to open \"%1\" for reading: %2") + .arg(projectFile.toUserOutput(), file.errorString()); + return QJsonObject(); + } + + const QByteArray content = file.readAll(); + + // This assumes the project file is formed with only one field called + // 'files' that has a list associated of the files to include in the project. + if (content.isEmpty()) { + *errorMessage = PythonProject::tr("Unable to read \"%1\": The file is empty.") + .arg(projectFile.toUserOutput()); + return QJsonObject(); + } + + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(content, &error); + if (doc.isNull()) { + const int line = content.left(error.offset).count('\n') + 1; + *errorMessage = PythonProject::tr("Unable to parse \"%1\":%2: %3") + .arg(projectFile.toUserOutput()).arg(line) + .arg(error.errorString()); + return QJsonObject(); + } + + return doc.object(); +} + static QStringList readLines(const FilePath &projectFile) { const QString projectFileName = projectFile.fileName(); @@ -127,37 +163,9 @@ static QStringList readLines(const FilePath &projectFile) static QStringList readLinesJson(const FilePath &projectFile, QString *errorMessage) { - const QString projectFileName = projectFile.fileName(); - QStringList lines = { projectFileName }; + QStringList lines = { projectFile.fileName() }; - QFile file(projectFile.toString()); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - *errorMessage = PythonProject::tr("Unable to open \"%1\" for reading: %2") - .arg(projectFile.toUserOutput(), file.errorString()); - return lines; - } - - const QByteArray content = file.readAll(); - - // This assumes the project file is formed with only one field called - // 'files' that has a list associated of the files to include in the project. - if (content.isEmpty()) { - *errorMessage = PythonProject::tr("Unable to read \"%1\": The file is empty.") - .arg(projectFile.toUserOutput()); - return lines; - } - - QJsonParseError error; - const QJsonDocument doc = QJsonDocument::fromJson(content, &error); - if (doc.isNull()) { - const int line = content.left(error.offset).count('\n') + 1; - *errorMessage = PythonProject::tr("Unable to parse \"%1\":%2: %3") - .arg(projectFile.toUserOutput()).arg(line) - .arg(error.errorString()); - return lines; - } - - const QJsonObject obj = doc.object(); + const QJsonObject obj = readObjJson(projectFile, errorMessage); if (obj.contains("files")) { const QJsonValue files = obj.value("files"); const QJsonArray files_array = files.toArray(); @@ -171,6 +179,26 @@ static QStringList readLinesJson(const FilePath &projectFile, QString *errorMess return lines; } +static QStringList readImportPathsJson(const FilePath &projectFile, QString *errorMessage) +{ + QStringList importPaths; + + const QJsonObject obj = readObjJson(projectFile, errorMessage); + if (obj.contains("qmlImportPaths")) { + const QJsonValue dirs = obj.value("qmlImportPaths"); + const QJsonArray dirs_array = dirs.toArray(); + + QSet<QString> visited; + + for (const auto &dir : dirs_array) + visited.insert(dir.toString()); + + importPaths.append(Utils::toList(visited)); + } + + return importPaths; +} + class PythonProjectNode : public ProjectNode { public: @@ -211,6 +239,7 @@ static FileType getFileType(const FilePath &f) void PythonBuildSystem::triggerParsing() { ParseGuard guard = guardParsingRun(); + parse(); const QDir baseDir(projectDirectory().toString()); @@ -235,6 +264,18 @@ void PythonBuildSystem::triggerParsing() setApplicationTargets(appTargets); + auto modelManager = QmlJS::ModelManagerInterface::instance(); + if (modelManager) { + auto projectInfo = modelManager->defaultProjectInfoForProject(project()); + + for (const QString &importPath : m_qmlImportPaths) { + const Utils::FilePath filePath = Utils::FilePath::fromString(importPath); + projectInfo.importPaths.maybeInsert(filePath, QmlJS::Dialect::Qml); + } + + modelManager->updateProjectInfo(projectInfo, project()); + } + guard.markAsSuccess(); emitBuildSystemUpdated(); @@ -355,6 +396,8 @@ bool PythonBuildSystem::renameFile(Node *, const QString &filePath, const QStrin void PythonBuildSystem::parse() { m_rawListEntries.clear(); + m_rawQmlImportPathEntries.clear(); + const FilePath filePath = projectFilePath(); // The PySide project file is JSON based if (filePath.endsWith(".pyproject")) { @@ -362,13 +405,19 @@ void PythonBuildSystem::parse() m_rawFileList = readLinesJson(filePath, &errorMessage); if (!errorMessage.isEmpty()) MessageManager::write(errorMessage); - } - // To keep compatibility with PyQt we keep the compatibility with plain - // text files as project files. - else if (filePath.endsWith(".pyqtc")) + + errorMessage.clear(); + m_rawQmlImportPathList = readImportPathsJson(filePath, &errorMessage); + if (!errorMessage.isEmpty()) + MessageManager::write(errorMessage); + } else if (filePath.endsWith(".pyqtc")) { + // To keep compatibility with PyQt we keep the compatibility with plain + // text files as project files. m_rawFileList = readLines(filePath); + } m_files = processEntries(m_rawFileList, &m_rawListEntries); + m_qmlImportPaths = processEntries(m_rawQmlImportPathList, &m_rawQmlImportPathEntries); } /** |