summaryrefslogtreecommitdiff
path: root/src/plugins/python/pythonproject.cpp
diff options
context:
space:
mode:
authorAlexander Mishin <apmishin@yandex.com>2020-09-21 19:39:24 +0300
committerAlexander Mishin <apmishin@yandex.com>2020-09-22 13:43:21 +0000
commit229dfaab95325ce64e27fe4503c8b99e5ec90bff (patch)
tree92ec0053afb057944ae96f84d0b652cde8410aee /src/plugins/python/pythonproject.cpp
parent31ec38dba5efb731b0769a2d3e4d0232d9ba6e22 (diff)
downloadqt-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.cpp119
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);
}
/**