Improve Qml code model import handling.

* Fill the snapshot with files that could be imported.
* Implement package imports.

* The qmldir file is not parsed yet.

Reviewed-by: Erik Verbruggen
This commit is contained in:
Christian Kamm
2010-03-16 16:34:33 +01:00
parent 62c41defb4
commit 9ea01cf5fb
17 changed files with 251 additions and 175 deletions

View File

@@ -671,7 +671,7 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
// Set up the current scope chain.
QList<AST::Node *> astPath = semanticInfo.astPath(editor->position());
context.build(astPath , document, snapshot);
context.build(astPath , document, snapshot, m_modelManager->importPaths());
// Search for the operator that triggered the completion.
QChar completionOperator;

View File

@@ -643,6 +643,7 @@ QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<ModelManagerInterface>();
if (m_modelManager) {
m_semanticHighlighter->setModelManager(m_modelManager);
connect(m_modelManager, SIGNAL(documentUpdated(QmlJS::Document::Ptr)),
this, SLOT(onDocumentUpdated(QmlJS::Document::Ptr)));
}
@@ -980,7 +981,8 @@ TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor &
Interpreter::Engine interp;
Interpreter::Context context(&interp);
context.build(semanticInfo.astPath(cursorPosition), semanticInfo.document, semanticInfo.snapshot);
context.build(semanticInfo.astPath(cursorPosition), semanticInfo.document,
semanticInfo.snapshot, m_modelManager->importPaths());
Evaluate check(&context);
const Interpreter::Value *value = check.reference(node);
@@ -1266,7 +1268,8 @@ SemanticHighlighter::Source QmlJSTextEditor::currentSource(bool force)
SemanticHighlighter::SemanticHighlighter(QObject *parent)
: QThread(parent),
m_done(false)
m_done(false),
m_modelManager(0)
{
}
@@ -1357,8 +1360,16 @@ SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
semanticInfo.snapshot = snapshot;
semanticInfo.document = doc;
Check checker(doc, snapshot);
QStringList importPaths;
if (m_modelManager)
importPaths = m_modelManager->importPaths();
Check checker(doc, snapshot, importPaths);
semanticInfo.semanticMessages = checker();
return semanticInfo;
}
void SemanticHighlighter::setModelManager(ModelManagerInterface *modelManager)
{
m_modelManager = modelManager;
}

View File

@@ -176,6 +176,7 @@ public:
};
void rehighlight(const Source &source);
void setModelManager(ModelManagerInterface *modelManager);
Q_SIGNALS:
void changed(const QmlJSEditor::Internal::SemanticInfo &semanticInfo);
@@ -193,6 +194,7 @@ private:
bool m_done;
Source m_source;
SemanticInfo m_lastSemanticInfo;
ModelManagerInterface *m_modelManager;
};
class QmlJSTextEditor : public TextEditor::BaseTextEditor

View File

@@ -172,7 +172,7 @@ void HoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int p
Interpreter::Engine interp;
Interpreter::Context context(&interp);
context.build(astPath, qmlDocument, snapshot);
context.build(astPath, qmlDocument, snapshot, m_modelManager->importPaths());
Evaluate check(&context);
const Interpreter::Value *value = check(node);

View File

@@ -39,8 +39,10 @@
#include <texteditor/itexteditor.h>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QLibraryInfo>
#include <QtConcurrentRun>
#include <qtconcurrent/runextensions.h>
#include <QTextStream>
@@ -51,6 +53,8 @@ using namespace QmlJS;
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
static QStringList environmentImportPaths();
ModelManager::ModelManager(QObject *parent):
ModelManagerInterface(parent),
m_core(Core::ICore::instance())
@@ -63,6 +67,10 @@ ModelManager::ModelManager(QObject *parent):
this, SLOT(onDocumentUpdated(QmlJS::Document::Ptr)));
loadQmlTypeDescriptions();
m_defaultImportPaths << environmentImportPaths();
m_defaultImportPaths << QLibraryInfo::location(QLibraryInfo::ImportsPath);
refreshSourceDirectories(m_defaultImportPaths);
}
void ModelManager::loadQmlTypeDescriptions()
@@ -124,6 +132,42 @@ QFuture<void> ModelManager::refreshSourceFiles(const QStringList &sourceFiles)
return result;
}
void ModelManager::updateSourceDirectories(const QStringList &directories)
{
refreshSourceDirectories(directories);
}
QFuture<void> ModelManager::refreshSourceDirectories(const QStringList &sourceDirectories)
{
if (sourceDirectories.isEmpty()) {
return QFuture<void>();
}
const QMap<QString, WorkingCopy> workingCopy = buildWorkingCopyList();
QFuture<void> result = QtConcurrent::run(&ModelManager::parseDirectories,
workingCopy, sourceDirectories,
this);
if (m_synchronizer.futures().size() > 10) {
QList<QFuture<void> > futures = m_synchronizer.futures();
m_synchronizer.clearFutures();
foreach (QFuture<void> future, futures) {
if (! (future.isFinished() || future.isCanceled()))
m_synchronizer.addFuture(future);
}
}
m_synchronizer.addFuture(result);
m_core->progressManager()->addTask(result, tr("Indexing"),
QmlJSEditor::Constants::TASK_INDEX);
return result;
}
QMap<QString, ModelManager::WorkingCopy> ModelManager::buildWorkingCopyList()
{
QMap<QString, WorkingCopy> workingCopy;
@@ -212,6 +256,32 @@ void ModelManager::parse(QFutureInterface<void> &future,
future.setProgressValue(files.size());
}
void ModelManager::parseDirectories(QFutureInterface<void> &future,
QMap<QString, WorkingCopy> workingCopy,
QStringList directories,
ModelManager *modelManager)
{
Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
Core::MimeType jsSourceTy = db->findByType(QLatin1String("application/javascript"));
Core::MimeType qmlSourceTy = db->findByType(QLatin1String("application/x-qml"));
QStringList pattern;
foreach (const QRegExp &glob, jsSourceTy.globPatterns())
pattern << glob.pattern();
foreach (const QRegExp &glob, qmlSourceTy.globPatterns())
pattern << glob.pattern();
QStringList importedFiles;
foreach (const QString &path, directories) {
QDirIterator fileIterator(path, pattern, QDir::Files,
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
while (fileIterator.hasNext())
importedFiles << fileIterator.next();
}
parse(future, workingCopy, importedFiles, modelManager);
}
// Check whether fileMimeType is the same or extends knownMimeType
bool ModelManager::matchesMimeType(const Core::MimeType &fileMimeType, const Core::MimeType &knownMimeType)
{
@@ -231,3 +301,38 @@ bool ModelManager::matchesMimeType(const Core::MimeType &fileMimeType, const Cor
return false;
}
void ModelManager::setProjectImportPaths(const QStringList &importPaths)
{
m_projectImportPaths = importPaths;
refreshSourceDirectories(importPaths);
}
QStringList ModelManager::importPaths() const
{
QStringList paths;
paths << m_projectImportPaths;
paths << m_defaultImportPaths;
return paths;
}
static QStringList environmentImportPaths()
{
QStringList paths;
QByteArray envImportPath = qgetenv("QML_IMPORT_PATH");
#if defined(Q_OS_WIN)
QLatin1Char pathSep(';');
#else
QLatin1Char pathSep(':');
#endif
foreach (const QString &path, QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts)) {
QString canonicalPath = QDir(path).canonicalPath();
if (!canonicalPath.isEmpty() && !paths.contains(canonicalPath))
paths.append(canonicalPath);
}
return paths;
}

View File

@@ -55,9 +55,13 @@ public:
virtual QmlJS::Snapshot snapshot() const;
virtual void updateSourceFiles(const QStringList &files);
virtual void updateSourceDirectories(const QStringList &directories);
void emitDocumentUpdated(QmlJS::Document::Ptr doc);
virtual void setProjectImportPaths(const QStringList &importPaths);
virtual QStringList importPaths() const;
Q_SIGNALS:
void projectPathChanged(const QString &projectPath);
void aboutToRemoveFiles(const QStringList &files);
@@ -75,6 +79,7 @@ protected:
};
QFuture<void> refreshSourceFiles(const QStringList &sourceFiles);
QFuture<void> refreshSourceDirectories(const QStringList &sourceDirectories);
QMap<QString, WorkingCopy> buildWorkingCopyList();
static void parse(QFutureInterface<void> &future,
@@ -82,6 +87,11 @@ protected:
QStringList files,
ModelManager *modelManager);
static void parseDirectories(QFutureInterface<void> &future,
QMap<QString, WorkingCopy> workingCopy,
QStringList directories,
ModelManager *modelManager);
void loadQmlTypeDescriptions();
private:
@@ -90,6 +100,8 @@ private:
mutable QMutex m_mutex;
Core::ICore *m_core;
QmlJS::Snapshot _snapshot;
QStringList m_projectImportPaths;
QStringList m_defaultImportPaths;
QFutureSynchronizer<void> m_synchronizer;
};

View File

@@ -54,6 +54,10 @@ public:
virtual QmlJS::Snapshot snapshot() const = 0;
virtual void updateSourceFiles(const QStringList &files) = 0;
virtual void updateSourceDirectories(const QStringList &directories) = 0;
virtual void setProjectImportPaths(const QStringList &importPaths) = 0;
virtual QStringList importPaths() const = 0;
signals:
void documentUpdated(QmlJS::Document::Ptr doc);