Automatic qmlls support (experimental)

Looks for qmlls (the qml language server of Qt) and if available
and set in the preferences uses it instead of the embedded code
model for the supported features.

Its usage is driven by two flags that can be set in the QtQuick > QML/JS
Editing preferences: "use qmlls" activates the use of qmlls if available;
"use latest qmlls" always uses the qmlls of the latest Qt, instead of
the one of the target (with the one used to compile QtCreator as
fallback).

To support disabling/enabling of qmlls as soon as one changes the
preferences the singleton QmllsSettingsManager can emit a signal
on changes.
It also keeps track of the latest qmlls binary known.

QmlJS::ModelmanagerInterface::ProjectInfo is also extended to keep track
of the qmlls binary.

QmlJSEditorDocument uses the ProjectInfo and QmllsSettingsManager to
decide if a LanguageClient::Client should be started for that
document.

The client uses the QmllsClient subclass to keep track of the path of
the qmlls clients and use the same qmlls process or all files that
use the same binary.

Currently qmlls <6.4.0 are not considered because they might have too
many issues.

The enabling/disabling of warnings and highlight is a bit cumbersome
because they are handled together in the semantic highlighter, but
must be handled separately depending on the qmlls capabilities.

The disabling is done at the latest moment stopping the visualization
of the embedded model warnings/highlights/suggestions.
The computation of the semantic info is not suppressed to support the
other features (find usages, semantic highlighting if active,...).
When qmlls supports more features a complete removal of the semantic
info construction could be evaluated.

Change-Id: I3487e1680841025cabba6b339fbfe820ef83f858
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Fawzi Mohamed
2022-09-28 11:16:49 +02:00
parent 634ac23af7
commit 3baf305f9b
17 changed files with 575 additions and 44 deletions

View File

@@ -113,6 +113,9 @@ ModelManagerInterface::ModelManagerInterface(QObject *parent)
m_defaultProjectInfo.qtQmlPath = m_defaultProjectInfo.qtQmlPath =
FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath));
m_defaultProjectInfo.qmllsPath = ModelManagerInterface::qmllsForBinPath(
FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::BinariesPath)),
QLibraryInfo::version());
m_defaultProjectInfo.qtVersionString = QLibraryInfo::version().toString(); m_defaultProjectInfo.qtVersionString = QLibraryInfo::version().toString();
updateImportPaths(); updateImportPaths();
@@ -216,6 +219,16 @@ ModelManagerInterface::WorkingCopy ModelManagerInterface::workingCopy()
return WorkingCopy(); return WorkingCopy();
} }
FilePath ModelManagerInterface::qmllsForBinPath(const Utils::FilePath &binPath, const QVersionNumber &version)
{
if (version < QVersionNumber(6,4,0))
return {};
QString qmllsExe = "qmlls";
if (HostOsInfo::isWindowsHost())
qmllsExe = "qmlls.exe";
return binPath.resolvePath(qmllsExe);
}
void ModelManagerInterface::activateScan() void ModelManagerInterface::activateScan()
{ {
if (!m_shouldScanImports) { if (!m_shouldScanImports) {
@@ -415,6 +428,10 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1,
return true; return true;
if (p1.qtQmlPath > p2.qtQmlPath) if (p1.qtQmlPath > p2.qtQmlPath)
return false; return false;
if (p1.qmllsPath < p2.qmllsPath)
return true;
if (p1.qmllsPath > p2.qmllsPath)
return false;
const PathsAndLanguages &s1 = p1.importPaths; const PathsAndLanguages &s1 = p1.importPaths;
const PathsAndLanguages &s2 = p2.importPaths; const PathsAndLanguages &s2 = p2.importPaths;
if (s1.size() < s2.size()) if (s1.size() < s2.size())
@@ -628,6 +645,8 @@ ModelManagerInterface::ProjectInfo ModelManagerInterface::projectInfoForPath(
res.qtQmlPath = pInfo.qtQmlPath; res.qtQmlPath = pInfo.qtQmlPath;
res.qtVersionString = pInfo.qtVersionString; res.qtVersionString = pInfo.qtVersionString;
} }
if (res.qmllsPath.isEmpty())
res.qmllsPath = pInfo.qmllsPath;
res.applicationDirectories.append(pInfo.applicationDirectories); res.applicationDirectories.append(pInfo.applicationDirectories);
for (const auto &importPath : pInfo.importPaths) for (const auto &importPath : pInfo.importPaths)
res.importPaths.maybeInsert(importPath); res.importPaths.maybeInsert(importPath);

View File

@@ -20,6 +20,7 @@
#include <QPointer> #include <QPointer>
#include <QStringList> #include <QStringList>
#include <QThreadPool> #include <QThreadPool>
#include <QVersionNumber>
QT_FORWARD_DECLARE_CLASS(QTimer) QT_FORWARD_DECLARE_CLASS(QTimer)
@@ -62,6 +63,7 @@ public:
Utils::Environment qmlDumpEnvironment; Utils::Environment qmlDumpEnvironment;
Utils::FilePath qtQmlPath; Utils::FilePath qtQmlPath;
Utils::FilePath qmllsPath;
QString qtVersionString; QString qtVersionString;
QmlJS::QmlLanguageBundles activeBundle; QmlJS::QmlLanguageBundles activeBundle;
QmlJS::QmlLanguageBundles extendedBundle; QmlJS::QmlLanguageBundles extendedBundle;
@@ -109,6 +111,7 @@ public:
static ModelManagerInterface *instanceForFuture(const QFuture<void> &future); static ModelManagerInterface *instanceForFuture(const QFuture<void> &future);
static void writeWarning(const QString &msg); static void writeWarning(const QString &msg);
static WorkingCopy workingCopy(); static WorkingCopy workingCopy();
static Utils::FilePath qmllsForBinPath(const Utils::FilePath &binPath, const QVersionNumber &v);
QmlJS::Snapshot snapshot() const; QmlJS::Snapshot snapshot() const;
QmlJS::Snapshot newestSnapshot() const; QmlJS::Snapshot newestSnapshot() const;

View File

@@ -1,8 +1,10 @@
add_qtc_plugin(QmlJSEditor add_qtc_plugin(QmlJSEditor
DEPENDS LanguageUtils QmlJS QmlEditorWidgets DEPENDS LanguageUtils QmlJS QmlEditorWidgets
PLUGIN_DEPENDS Core ProjectExplorer QmlJSTools TextEditor PLUGIN_DEPENDS Core ProjectExplorer QmlJSTools TextEditor LanguageClient
SOURCES SOURCES
qmlexpressionundercursor.cpp qmlexpressionundercursor.h qmlexpressionundercursor.cpp qmlexpressionundercursor.h
qmllsclient.h qmllsclient.cpp
qmllssettings.h qmllssettings.cpp
qmljsautocompleter.cpp qmljsautocompleter.h qmljsautocompleter.cpp qmljsautocompleter.h
qmljscompletionassist.cpp qmljscompletionassist.h qmljscompletionassist.cpp qmljscompletionassist.h
qmljscomponentfromobjectdef.cpp qmljscomponentfromobjectdef.h qmljscomponentfromobjectdef.cpp qmljscomponentfromobjectdef.h

View File

@@ -20,20 +20,13 @@ const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "QmlJSEditor.AutoFormatOnlyCurre
const char QML_CONTEXTPANE_KEY[] = "QmlJSEditor.ContextPaneEnabled"; const char QML_CONTEXTPANE_KEY[] = "QmlJSEditor.ContextPaneEnabled";
const char QML_CONTEXTPANEPIN_KEY[] = "QmlJSEditor.ContextPanePinned"; const char QML_CONTEXTPANEPIN_KEY[] = "QmlJSEditor.ContextPanePinned";
const char FOLD_AUX_DATA[] = "QmlJSEditor.FoldAuxData"; const char FOLD_AUX_DATA[] = "QmlJSEditor.FoldAuxData";
const char USE_QMLLS[] = "QmlJSEditor.UseQmlls";
const char USE_LATEST_QMLLS[] = "QmlJSEditor.UseLatestQmlls";
const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode"; const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode";
using namespace QmlJSEditor; using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal; using namespace QmlJSEditor::Internal;
QmlJsEditingSettings::QmlJsEditingSettings()
: m_enableContextPane(false),
m_pinContextPane(false),
m_autoFormatOnSave(false),
m_autoFormatOnlyCurrentProject(false),
m_foldAuxData(false),
m_uiQmlOpenMode("")
{}
void QmlJsEditingSettings::set() void QmlJsEditingSettings::set()
{ {
if (get() != *this) if (get() != *this)
@@ -50,6 +43,8 @@ void QmlJsEditingSettings::fromSettings(QSettings *settings)
= settings->value(AUTO_FORMAT_ONLY_CURRENT_PROJECT, QVariant(false)).toBool(); = settings->value(AUTO_FORMAT_ONLY_CURRENT_PROJECT, QVariant(false)).toBool();
m_foldAuxData = settings->value(FOLD_AUX_DATA, QVariant(true)).toBool(); m_foldAuxData = settings->value(FOLD_AUX_DATA, QVariant(true)).toBool();
m_uiQmlOpenMode = settings->value(UIQML_OPEN_MODE, "").toString(); m_uiQmlOpenMode = settings->value(UIQML_OPEN_MODE, "").toString();
m_qmllsSettings.useQmlls = settings->value(USE_QMLLS, QVariant(false)).toBool();
m_qmllsSettings.useLatestQmlls = settings->value(USE_LATEST_QMLLS, QVariant(false)).toBool();
settings->endGroup(); settings->endGroup();
} }
@@ -62,7 +57,10 @@ void QmlJsEditingSettings::toSettings(QSettings *settings) const
settings->setValue(AUTO_FORMAT_ONLY_CURRENT_PROJECT, m_autoFormatOnlyCurrentProject); settings->setValue(AUTO_FORMAT_ONLY_CURRENT_PROJECT, m_autoFormatOnlyCurrentProject);
settings->setValue(FOLD_AUX_DATA, m_foldAuxData); settings->setValue(FOLD_AUX_DATA, m_foldAuxData);
settings->setValue(UIQML_OPEN_MODE, m_uiQmlOpenMode); settings->setValue(UIQML_OPEN_MODE, m_uiQmlOpenMode);
settings->setValue(USE_QMLLS, m_qmllsSettings.useQmlls);
settings->setValue(USE_LATEST_QMLLS, m_qmllsSettings.useLatestQmlls);
settings->endGroup(); settings->endGroup();
QmllsSettingsManager::instance()->checkForChanges();
} }
bool QmlJsEditingSettings::equals(const QmlJsEditingSettings &other) const bool QmlJsEditingSettings::equals(const QmlJsEditingSettings &other) const
@@ -72,6 +70,7 @@ bool QmlJsEditingSettings::equals(const QmlJsEditingSettings &other) const
&& m_autoFormatOnSave == other.m_autoFormatOnSave && m_autoFormatOnSave == other.m_autoFormatOnSave
&& m_autoFormatOnlyCurrentProject == other.m_autoFormatOnlyCurrentProject && m_autoFormatOnlyCurrentProject == other.m_autoFormatOnlyCurrentProject
&& m_foldAuxData == other.m_foldAuxData && m_foldAuxData == other.m_foldAuxData
&& m_qmllsSettings == other.m_qmllsSettings
&& m_uiQmlOpenMode == other.m_uiQmlOpenMode; && m_uiQmlOpenMode == other.m_uiQmlOpenMode;
} }
@@ -125,6 +124,16 @@ void QmlJsEditingSettings::setFoldAuxData(const bool foldAuxData)
m_foldAuxData = foldAuxData; m_foldAuxData = foldAuxData;
} }
QmllsSettings &QmlJsEditingSettings::qmllsSettigs()
{
return m_qmllsSettings;
}
const QmllsSettings &QmlJsEditingSettings::qmllsSettigs() const
{
return m_qmllsSettings;
}
const QString QmlJsEditingSettings::uiQmlOpenMode() const const QString QmlJsEditingSettings::uiQmlOpenMode() const
{ {
return m_uiQmlOpenMode; return m_uiQmlOpenMode;
@@ -162,6 +171,14 @@ public:
uiQmlOpenComboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); uiQmlOpenComboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
uiQmlOpenComboBox->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents); uiQmlOpenComboBox->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents);
useQmlls = new QCheckBox(tr("Use qmlls (EXPERIMENTAL!)"));
useQmlls->setChecked(s.qmllsSettigs().useQmlls);
useLatestQmlls = new QCheckBox(tr("Always use latest qmlls"));
useLatestQmlls->setChecked(s.qmllsSettigs().useLatestQmlls);
useLatestQmlls->setEnabled(s.qmllsSettigs().useQmlls);
QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) {
useLatestQmlls->setEnabled(checked != Qt::Unchecked);
});
using namespace Utils::Layouting; using namespace Utils::Layouting;
Column { Column {
Group { Group {
@@ -179,8 +196,13 @@ public:
Form { Tr::tr("Open .ui.qml files with:"), uiQmlOpenComboBox }, Form { Tr::tr("Open .ui.qml files with:"), uiQmlOpenComboBox },
}, },
}, },
Group{
title(tr("Language Server")),
Column{useQmlls, useLatestQmlls},
},
st, st,
}.attachTo(this); }
.attachTo(this);
connect(autoFormatOnSave, &QCheckBox::toggled, connect(autoFormatOnSave, &QCheckBox::toggled,
autoFormatOnlyCurrentProject, &QWidget::setEnabled); autoFormatOnlyCurrentProject, &QWidget::setEnabled);
@@ -195,6 +217,8 @@ public:
s.setAutoFormatOnlyCurrentProject(autoFormatOnlyCurrentProject->isChecked()); s.setAutoFormatOnlyCurrentProject(autoFormatOnlyCurrentProject->isChecked());
s.setFoldAuxData(foldAuxData->isChecked()); s.setFoldAuxData(foldAuxData->isChecked());
s.setUiQmlOpenMode(uiQmlOpenComboBox->currentData().toString()); s.setUiQmlOpenMode(uiQmlOpenComboBox->currentData().toString());
s.qmllsSettigs().useQmlls = useQmlls->isChecked();
s.qmllsSettigs().useLatestQmlls = useLatestQmlls->isChecked();
s.set(); s.set();
} }
@@ -204,6 +228,8 @@ private:
QCheckBox *pinContextPane; QCheckBox *pinContextPane;
QCheckBox *enableContextPane; QCheckBox *enableContextPane;
QCheckBox *foldAuxData; QCheckBox *foldAuxData;
QCheckBox *useQmlls;
QCheckBox *useLatestQmlls;
QComboBox *uiQmlOpenComboBox; QComboBox *uiQmlOpenComboBox;
}; };
@@ -222,4 +248,3 @@ QmlJsEditingSettingsPage::QmlJsEditingSettingsPage()
setCategory(Constants::SETTINGS_CATEGORY_QML); setCategory(Constants::SETTINGS_CATEGORY_QML);
setWidgetCreator([] { return new QmlJsEditingSettingsPageWidget; }); setWidgetCreator([] { return new QmlJsEditingSettingsPageWidget; });
} }

View File

@@ -3,6 +3,7 @@
#pragma once #pragma once
#include "qmllssettings.h"
#include <coreplugin/dialogs/ioptionspage.h> #include <coreplugin/dialogs/ioptionspage.h>
#include <QPointer> #include <QPointer>
#include <QWidget> #include <QWidget>
@@ -16,7 +17,7 @@ namespace QmlJSEditor {
class QmlJsEditingSettings class QmlJsEditingSettings
{ {
public: public:
QmlJsEditingSettings(); QmlJsEditingSettings() = default;
static QmlJsEditingSettings get(); static QmlJsEditingSettings get();
void set(); void set();
@@ -41,6 +42,9 @@ public:
bool foldAuxData() const; bool foldAuxData() const;
void setFoldAuxData(const bool foldAuxData); void setFoldAuxData(const bool foldAuxData);
QmllsSettings &qmllsSettigs();
const QmllsSettings &qmllsSettigs() const;
const QString uiQmlOpenMode() const; const QString uiQmlOpenMode() const;
void setUiQmlOpenMode(const QString &mode); void setUiQmlOpenMode(const QString &mode);
@@ -50,12 +54,13 @@ public:
{ return !s1.equals(s2); } { return !s1.equals(s2); }
private: private:
bool m_enableContextPane; bool m_enableContextPane = false;
bool m_pinContextPane; bool m_pinContextPane = false;
bool m_autoFormatOnSave; bool m_autoFormatOnSave = false;
bool m_autoFormatOnlyCurrentProject; bool m_autoFormatOnlyCurrentProject = false;
bool m_foldAuxData; bool m_foldAuxData = true;
QString m_uiQmlOpenMode; QmllsSettings m_qmllsSettings;
QString m_uiQmlOpenMode = {};
}; };
namespace Internal { namespace Internal {

View File

@@ -13,10 +13,15 @@ QtcPlugin {
Depends { name: "TextEditor" } Depends { name: "TextEditor" }
Depends { name: "ProjectExplorer" } Depends { name: "ProjectExplorer" }
Depends { name: "QmlJSTools" } Depends { name: "QmlJSTools" }
Depends { name: "LanguageClient" }
files: [ files: [
"qmlexpressionundercursor.cpp", "qmlexpressionundercursor.cpp",
"qmlexpressionundercursor.h", "qmlexpressionundercursor.h",
"qmllsclient.cpp",
"qmllsclient.h",
"qmllssettings.cpp",
"qmllssettings.h",
"qmljsautocompleter.cpp", "qmljsautocompleter.cpp",
"qmljsautocompleter.h", "qmljsautocompleter.h",
"qmljscompletionassist.cpp", "qmljscompletionassist.cpp",

View File

@@ -12,6 +12,8 @@
#include "qmljssemantichighlighter.h" #include "qmljssemantichighlighter.h"
#include "qmljssemanticinfoupdater.h" #include "qmljssemanticinfoupdater.h"
#include "qmljstextmark.h" #include "qmljstextmark.h"
#include "qmllsclient.h"
#include "qmllssettings.h"
#include "qmloutlinemodel.h" #include "qmloutlinemodel.h"
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
@@ -24,7 +26,10 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/infobar.h> #include <utils/infobar.h>
#include <languageclient/languageclientmanager.h>
#include <QDebug> #include <QDebug>
#include <QLoggingCategory>
#include <QTextCodec> #include <QTextCodec>
const char QML_UI_FILE_WARNING[] = "QmlJSEditor.QmlUiFileWarning"; const char QML_UI_FILE_WARNING[] = "QmlJSEditor.QmlUiFileWarning";
@@ -36,6 +41,8 @@ using namespace QmlJSTools;
namespace { namespace {
Q_LOGGING_CATEGORY(qmllsLog, "qtc.qmlls.editor", QtWarningMsg);
enum { enum {
UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100, UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100,
UPDATE_OUTLINE_INTERVAL = 500 UPDATE_OUTLINE_INTERVAL = 500
@@ -471,6 +478,10 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare
this, &QmlJSEditorDocumentPrivate::reparseDocument); this, &QmlJSEditorDocumentPrivate::reparseDocument);
connect(modelManager, &ModelManagerInterface::documentUpdated, connect(modelManager, &ModelManagerInterface::documentUpdated,
this, &QmlJSEditorDocumentPrivate::onDocumentUpdated); this, &QmlJSEditorDocumentPrivate::onDocumentUpdated);
connect(QmllsSettingsManager::instance(),
&QmllsSettingsManager::settingsChanged,
this,
&Internal::QmlJSEditorDocumentPrivate::settingsChanged);
// semantic info // semantic info
m_semanticInfoUpdater = new SemanticInfoUpdater(this); m_semanticInfoUpdater = new SemanticInfoUpdater(this);
@@ -493,6 +504,7 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare
this, &QmlJSEditorDocumentPrivate::updateOutlineModel); this, &QmlJSEditorDocumentPrivate::updateOutlineModel);
modelManager->updateSourceFiles(Utils::FilePaths({parent->filePath()}), false); modelManager->updateSourceFiles(Utils::FilePaths({parent->filePath()}), false);
settingsChanged();
} }
QmlJSEditorDocumentPrivate::~QmlJSEditorDocumentPrivate() QmlJSEditorDocumentPrivate::~QmlJSEditorDocumentPrivate()
@@ -530,7 +542,8 @@ void QmlJSEditorDocumentPrivate::onDocumentUpdated(Document::Ptr doc)
// got a correctly parsed (or recovered) file. // got a correctly parsed (or recovered) file.
m_semanticInfoDocRevision = doc->editorRevision(); m_semanticInfoDocRevision = doc->editorRevision();
m_semanticInfoUpdater->update(doc, ModelManagerInterface::instance()->snapshot()); m_semanticInfoUpdater->update(doc, ModelManagerInterface::instance()->snapshot());
} else if (doc->language().isFullySupportedLanguage()) { } else if (doc->language().isFullySupportedLanguage()
&& m_qmllsStatus.semanticWarningsSource == QmllsStatus::Source::EmbeddedCodeModel) {
createTextMarks(doc->diagnosticMessages()); createTextMarks(doc->diagnosticMessages());
} }
emit q->updateCodeWarnings(doc); emit q->updateCodeWarnings(doc);
@@ -567,7 +580,8 @@ void QmlJSEditorDocumentPrivate::acceptNewSemanticInfo(const SemanticInfo &seman
m_outlineModelNeedsUpdate = true; m_outlineModelNeedsUpdate = true;
m_semanticHighlightingNecessary = true; m_semanticHighlightingNecessary = true;
createTextMarks(m_semanticInfo); if (m_qmllsStatus.semanticWarningsSource == QmllsStatus::Source::EmbeddedCodeModel)
createTextMarks(m_semanticInfo);
emit q->semanticInfoUpdated(m_semanticInfo); // calls triggerPendingUpdates as necessary emit q->semanticInfoUpdated(m_semanticInfo); // calls triggerPendingUpdates as necessary
} }
@@ -594,6 +608,8 @@ static void cleanMarks(QVector<TextEditor::TextMark *> *marks, TextEditor::TextD
void QmlJSEditorDocumentPrivate::createTextMarks(const QList<DiagnosticMessage> &diagnostics) void QmlJSEditorDocumentPrivate::createTextMarks(const QList<DiagnosticMessage> &diagnostics)
{ {
if (m_qmllsStatus.semanticWarningsSource != QmllsStatus::Source::EmbeddedCodeModel)
return;
for (const DiagnosticMessage &diagnostic : diagnostics) { for (const DiagnosticMessage &diagnostic : diagnostics) {
const auto onMarkRemoved = [this](QmlJSTextMark *mark) { const auto onMarkRemoved = [this](QmlJSTextMark *mark) {
m_diagnosticMarks.removeAll(mark); m_diagnosticMarks.removeAll(mark);
@@ -637,6 +653,158 @@ void QmlJSEditorDocumentPrivate::cleanSemanticMarks()
cleanMarks(&m_semanticMarks, q); cleanMarks(&m_semanticMarks, q);
} }
void QmlJSEditorDocumentPrivate::setSemanticWarningSource(QmllsStatus::Source newSource)
{
if (m_qmllsStatus.semanticWarningsSource == newSource)
return;
m_qmllsStatus.semanticWarningsSource = newSource;
QTC_ASSERT(q->thread() == QThread::currentThread(), return );
switch (m_qmllsStatus.semanticWarningsSource) {
case QmllsStatus::Source::Qmlls:
m_semanticHighlighter->setEnableWarnings(false);
cleanDiagnosticMarks();
cleanSemanticMarks();
if (!q->isSemanticInfoOutdated()) {
// clean up underlines for warning messages
m_semanticHighlightingNecessary = false;
m_semanticHighlighter->rerun(m_semanticInfo);
}
break;
case QmllsStatus::Source::EmbeddedCodeModel:
m_semanticHighlighter->setEnableWarnings(true);
reparseDocument();
break;
}
}
void QmlJSEditorDocumentPrivate::setSemanticHighlightSource(QmllsStatus::Source newSource)
{
if (m_qmllsStatus.semanticHighlightSource == newSource)
return;
m_qmllsStatus.semanticHighlightSource = newSource;
QTC_ASSERT(q->thread() == QThread::currentThread(), return );
switch (m_qmllsStatus.semanticHighlightSource) {
case QmllsStatus::Source::Qmlls:
m_semanticHighlighter->setEnableHighlighting(false);
cleanSemanticMarks();
break;
case QmllsStatus::Source::EmbeddedCodeModel:
m_semanticHighlighter->setEnableHighlighting(true);
if (!q->isSemanticInfoOutdated()) {
m_semanticHighlightingNecessary = false;
m_semanticHighlighter->rerun(m_semanticInfo);
}
break;
}
}
void QmlJSEditorDocumentPrivate::setCompletionSource(QmllsStatus::Source newSource)
{
if (m_qmllsStatus.completionSource == newSource)
return;
m_qmllsStatus.completionSource = newSource;
switch (m_qmllsStatus.completionSource) {
case QmllsStatus::Source::Qmlls:
// activation of the document already takes care of setting it
break;
case QmllsStatus::Source::EmbeddedCodeModel:
// deactivation of the document takes care of restoring it
break;
}
}
void QmlJSEditorDocumentPrivate::setSourcesWithCapabilities(
const LanguageServerProtocol::ServerCapabilities &cap)
{
if (cap.completionProvider())
setCompletionSource(QmllsStatus::Source::Qmlls);
else
setCompletionSource(QmllsStatus::Source::EmbeddedCodeModel);
if (cap.codeActionProvider())
setSemanticWarningSource(QmllsStatus::Source::Qmlls);
else
setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel);
if (cap.semanticTokensProvider())
setSemanticHighlightSource(QmllsStatus::Source::Qmlls);
else
setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel);
}
static Utils::FilePath qmllsForFile(const Utils::FilePath &file,
QmlJS::ModelManagerInterface *modelManager)
{
QmllsSettingsManager *settingsManager = QmllsSettingsManager::instance();
QmllsSettings settings = settingsManager->lastSettings();
bool enabled = settings.useQmlls;
if (!enabled)
return Utils::FilePath();
if (settings.useLatestQmlls)
return settingsManager->latestQmlls();
QmlJS::ModelManagerInterface::ProjectInfo pInfo = modelManager->projectInfoForPath(file);
return pInfo.qmllsPath;
}
void QmlJSEditorDocumentPrivate::settingsChanged()
{
Utils::FilePath newQmlls = qmllsForFile(q->filePath(), ModelManagerInterface::instance());
if (m_qmllsStatus.qmllsPath == newQmlls)
return;
m_qmllsStatus.qmllsPath = newQmlls;
auto lspClientManager = LanguageClient::LanguageClientManager::instance();
if (newQmlls.isEmpty()) {
qCDebug(qmllsLog) << "disabling qmlls for" << q->filePath();
if (LanguageClient::Client *client = lspClientManager->clientForDocument(q)) {
qCDebug(qmllsLog) << "deactivating " << q->filePath() << "in qmlls" << newQmlls;
client->deactivateDocument(q);
} else
qCWarning(qmllsLog) << "Could not find client to disable for document " << q->filePath()
<< " in LanguageClient::LanguageClientManager";
setCompletionSource(QmllsStatus::Source::EmbeddedCodeModel);
setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel);
setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel);
} else if (QmllsClient *client = QmllsClient::clientForQmlls(newQmlls)) {
bool shouldActivate = false;
if (auto oldClient = lspClientManager->clientForDocument(q)) {
// check if it was disabled
if (client == oldClient)
shouldActivate = true;
}
switch (client->state()) {
case LanguageClient::Client::State::Uninitialized:
case LanguageClient::Client::State::InitializeRequested:
connect(client,
&LanguageClient::Client::initialized,
this,
&QmlJSEditorDocumentPrivate::setSourcesWithCapabilities);
break;
case LanguageClient::Client::State::Initialized:
setSourcesWithCapabilities(client->capabilities());
break;
case LanguageClient::Client::State::Error:
qCWarning(qmllsLog) << "qmlls" << newQmlls << "requested for document" << q->filePath()
<< "had errors, skipping setSourcesWithCababilities";
break;
case LanguageClient::Client::State::Shutdown:
qCWarning(qmllsLog) << "qmlls" << newQmlls << "requested for document" << q->filePath()
<< "did stop, skipping setSourcesWithCababilities";
break;
case LanguageClient::Client::State::ShutdownRequested:
qCWarning(qmllsLog) << "qmlls" << newQmlls << "requested for document" << q->filePath()
<< "is stopping, skipping setSourcesWithCababilities";
break;
}
if (shouldActivate) {
qCDebug(qmllsLog) << "reactivating " << q->filePath() << "in qmlls" << newQmlls;
client->activateDocument(q);
} else {
qCDebug(qmllsLog) << "opening " << q->filePath() << "in qmlls" << newQmlls;
lspClientManager->openDocumentWithClient(q, client);
}
} else {
qCWarning(qmllsLog) << "could not start qmlls " << newQmlls << "for" << q->filePath();
}
}
} // Internal } // Internal
QmlJSEditorDocument::QmlJSEditorDocument(Utils::Id id) QmlJSEditorDocument::QmlJSEditorDocument(Utils::Id id)

View File

@@ -3,6 +3,7 @@
#pragma once #pragma once
#include <languageserverprotocol/servercapabilities.h>
#include <qmljs/qmljsdocument.h> #include <qmljs/qmljsdocument.h>
#include <qmljstools/qmljssemanticinfo.h> #include <qmljstools/qmljssemanticinfo.h>
@@ -23,6 +24,17 @@ class QmlOutlineModel;
class SemanticInfoUpdater; class SemanticInfoUpdater;
class QmllsStatus
{
public:
enum class Source { Qmlls, EmbeddedCodeModel };
Source semanticWarningsSource;
Source semanticHighlightSource;
Source completionSource;
Utils::FilePath qmllsPath;
};
class QmlJSEditorDocumentPrivate : public QObject class QmlJSEditorDocumentPrivate : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -43,6 +55,14 @@ public:
void createTextMarks(const QmlJSTools::SemanticInfo &info); void createTextMarks(const QmlJSTools::SemanticInfo &info);
void cleanSemanticMarks(); void cleanSemanticMarks();
// qmlls change source
void setSemanticWarningSource(QmllsStatus::Source newSource);
void setSemanticHighlightSource(QmllsStatus::Source newSource);
void setCompletionSource(QmllsStatus::Source newSource);
public slots:
void setSourcesWithCapabilities(const LanguageServerProtocol::ServerCapabilities &);
void settingsChanged();
public: public:
QmlJSEditorDocument *q = nullptr; QmlJSEditorDocument *q = nullptr;
QTimer m_updateDocumentTimer; // used to compress multiple document changes QTimer m_updateDocumentTimer; // used to compress multiple document changes
@@ -59,6 +79,10 @@ public:
QVector<TextEditor::TextMark *> m_diagnosticMarks; QVector<TextEditor::TextMark *> m_diagnosticMarks;
QVector<TextEditor::TextMark *> m_semanticMarks; QVector<TextEditor::TextMark *> m_semanticMarks;
bool m_isDesignModePreferred = false; bool m_isDesignModePreferred = false;
QmllsStatus m_qmllsStatus = {QmllsStatus::Source::EmbeddedCodeModel,
QmllsStatus::Source::EmbeddedCodeModel,
QmllsStatus::Source::EmbeddedCodeModel,
{}};
}; };
} // Internal } // Internal

View File

@@ -114,6 +114,7 @@ QmlJSEditorPluginPrivate::QmlJSEditorPluginPrivate()
&QmlJSEditorFactory::decorateEditor); &QmlJSEditorFactory::decorateEditor);
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
QmllsSettingsManager::instance();
// QML task updating manager // QML task updating manager
connect(modelManager, &QmlJS::ModelManagerInterface::documentChangedOnDisk, connect(modelManager, &QmlJS::ModelManagerInterface::documentChangedOnDisk,
@@ -207,6 +208,7 @@ void QmlJSEditorPlugin::extensionsInitialized()
TaskHub::addCategory(Constants::TASK_CATEGORY_QML, Tr::tr("QML")); TaskHub::addCategory(Constants::TASK_CATEGORY_QML, Tr::tr("QML"));
TaskHub::addCategory(Constants::TASK_CATEGORY_QML_ANALYSIS, Tr::tr("QML Analysis"), false); TaskHub::addCategory(Constants::TASK_CATEGORY_QML_ANALYSIS, Tr::tr("QML Analysis"), false);
QmllsSettingsManager::instance()->setupAutoupdate();
} }
ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown() ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown()

View File

@@ -152,9 +152,14 @@ protected:
class CollectionTask : protected Visitor class CollectionTask : protected Visitor
{ {
public: public:
enum Flags {
AddMessagesHighlights,
SkipMessagesHighlights,
};
CollectionTask(QFutureInterface<SemanticHighlighter::Use> &futureInterface, CollectionTask(QFutureInterface<SemanticHighlighter::Use> &futureInterface,
const QmlJSTools::SemanticInfo &semanticInfo, const QmlJSTools::SemanticInfo &semanticInfo,
const TextEditor::FontSettings &fontSettings) const TextEditor::FontSettings &fontSettings,
Flags flags)
: m_futureInterface(futureInterface) : m_futureInterface(futureInterface)
, m_semanticInfo(semanticInfo) , m_semanticInfo(semanticInfo)
, m_fontSettings(fontSettings) , m_fontSettings(fontSettings)
@@ -172,9 +177,11 @@ public:
m_delayedUses.reserve(nMessages); m_delayedUses.reserve(nMessages);
m_diagnosticRanges.reserve(nMessages); m_diagnosticRanges.reserve(nMessages);
m_extraFormats.reserve(nMessages); m_extraFormats.reserve(nMessages);
addMessages(m_scopeChain.document()->diagnosticMessages(), m_scopeChain.document()); if (flags == AddMessagesHighlights) {
addMessages(m_semanticInfo.semanticMessages, m_semanticInfo.document); addMessages(m_scopeChain.document()->diagnosticMessages(), m_scopeChain.document());
addMessages(m_semanticInfo.staticAnalysisMessages, m_semanticInfo.document); addMessages(m_semanticInfo.semanticMessages, m_semanticInfo.document);
addMessages(m_semanticInfo.staticAnalysisMessages, m_semanticInfo.document);
}
Utils::sort(m_delayedUses, sortByLinePredicate); Utils::sort(m_delayedUses, sortByLinePredicate);
} }
@@ -563,8 +570,9 @@ void SemanticHighlighter::applyResults(int from, int to)
if (m_startRevision != m_document->document()->revision()) if (m_startRevision != m_document->document()->revision())
return; return;
TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats( if (m_enableHighlighting)
m_document->syntaxHighlighter(), m_watcher.future(), from, to, m_extraFormats); TextEditor::SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
m_document->syntaxHighlighter(), m_watcher.future(), from, to, m_extraFormats);
} }
void SemanticHighlighter::finished() void SemanticHighlighter::finished()
@@ -574,17 +582,23 @@ void SemanticHighlighter::finished()
if (m_startRevision != m_document->document()->revision()) if (m_startRevision != m_document->document()->revision())
return; return;
m_document->setDiagnosticRanges(m_diagnosticRanges); if (m_enableWarnings)
m_document->setDiagnosticRanges(m_diagnosticRanges);
TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd( if (m_enableHighlighting)
m_document->syntaxHighlighter(), m_watcher.future()); TextEditor::SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(
m_document->syntaxHighlighter(), m_watcher.future());
} }
void SemanticHighlighter::run(QFutureInterface<SemanticHighlighter::Use> &futureInterface, void SemanticHighlighter::run(QFutureInterface<SemanticHighlighter::Use> &futureInterface,
const QmlJSTools::SemanticInfo &semanticInfo, const QmlJSTools::SemanticInfo &semanticInfo,
const TextEditor::FontSettings &fontSettings) const TextEditor::FontSettings &fontSettings)
{ {
CollectionTask task(futureInterface, semanticInfo, fontSettings); CollectionTask task(futureInterface,
semanticInfo,
fontSettings,
(m_enableWarnings ? CollectionTask::AddMessagesHighlights
: CollectionTask::SkipMessagesHighlights));
reportMessagesInfo(task.diagnosticRanges(), task.extraFormats()); reportMessagesInfo(task.diagnosticRanges(), task.extraFormats());
task.run(); task.run();
} }
@@ -622,4 +636,14 @@ int SemanticHighlighter::startRevision() const
return m_startRevision; return m_startRevision;
} }
void SemanticHighlighter::setEnableWarnings(bool e)
{
m_enableWarnings = e;
}
void SemanticHighlighter::setEnableHighlighting(bool e)
{
m_enableHighlighting = e;
}
} // namespace QmlJSEditor } // namespace QmlJSEditor

View File

@@ -52,6 +52,8 @@ public:
void cancel(); void cancel();
int startRevision() const; int startRevision() const;
void setEnableWarnings(bool e);
void setEnableHighlighting(bool e);
void updateFontSettings(const TextEditor::FontSettings &fontSettings); void updateFontSettings(const TextEditor::FontSettings &fontSettings);
void reportMessagesInfo(const QVector<QTextLayout::FormatRange> &diagnosticMessages, void reportMessagesInfo(const QVector<QTextLayout::FormatRange> &diagnosticMessages,
@@ -71,6 +73,8 @@ private:
QHash<int, QTextCharFormat> m_extraFormats; QHash<int, QTextCharFormat> m_extraFormats;
QVector<QTextLayout::FormatRange> m_diagnosticRanges; QVector<QTextLayout::FormatRange> m_diagnosticRanges;
Utils::FutureSynchronizer m_futureSynchronizer; Utils::FutureSynchronizer m_futureSynchronizer;
bool m_enableWarnings = true;
bool m_enableHighlighting = true;
}; };
} // namespace QmlJSEditor } // namespace QmlJSEditor

View File

@@ -0,0 +1,73 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "qmllsclient.h"
#include <languageclient/languageclientinterface.h>
#include <languageclient/languageclientmanager.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljstools/qmljstoolsconstants.h>
#include <QLoggingCategory>
using namespace LanguageClient;
using namespace Utils;
namespace {
Q_LOGGING_CATEGORY(qmllsLog, "qtc.qmlls.client", QtWarningMsg);
}
namespace QmlJSEditor {
static QHash<FilePath, QmllsClient *> &qmllsClients()
{
static QHash<FilePath, QmllsClient *> clients;
return clients;
}
QmllsClient *QmllsClient::clientForQmlls(const FilePath &qmlls)
{
if (auto client = qmllsClients()[qmlls]) {
switch (client->state()) {
case Client::State::Uninitialized:
case Client::State::InitializeRequested:
case Client::State::Initialized:
return client;
case Client::State::ShutdownRequested:
case Client::State::Shutdown:
case Client::State::Error:
qCDebug(qmllsLog) << "client was stopping or failed, restarting";
break;
}
}
auto interface = new StdIOClientInterface;
interface->setCommandLine(CommandLine(qmlls));
auto client = new QmllsClient(interface);
client->setName(QmllsClient::tr("Qmlls (%1)").arg(qmlls.toUserOutput()));
client->setActivateDocumentAutomatically(true);
LanguageFilter filter;
using namespace QmlJSTools::Constants;
filter.mimeTypes = QStringList()
<< QML_MIMETYPE << QMLUI_MIMETYPE << QBS_MIMETYPE << QMLPROJECT_MIMETYPE
<< QMLTYPES_MIMETYPE << JS_MIMETYPE << JSON_MIMETYPE;
client->setSupportedLanguage(filter);
client->start();
qmllsClients()[qmlls] = client;
return client;
}
QmllsClient::QmllsClient(StdIOClientInterface *interface)
: Client(interface)
{
}
QmllsClient::~QmllsClient()
{
qmllsClients().remove(qmllsClients().key(this));
}
} // namespace QmlJSEditor

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include "qmljseditor_global.h"
#include <utils/fileutils.h>
#include <languageclient/client.h>
#include <languageclient/languageclientinterface.h>
namespace QmlJSEditor {
class QMLJSEDITOR_EXPORT QmllsClient : public LanguageClient::Client
{
Q_OBJECT
public:
explicit QmllsClient(LanguageClient::StdIOClientInterface *interface);
~QmllsClient();
static QmllsClient *clientForQmlls(const Utils::FilePath &qmlls);
};
} // namespace QmlJSEditor

View File

@@ -0,0 +1,106 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "qmllssettings.h"
#include "qmljseditingsettingspage.h"
#include <utils/hostosinfo.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <QLoggingCategory>
#include <qtsupport/qtversionmanager.h>
#include <limits>
using namespace QtSupport;
using namespace Utils;
namespace QmlJSEditor {
namespace {
Q_LOGGING_CATEGORY(qmllsLog, "qtc.qmlls.settings", QtWarningMsg);
}
static FilePath evaluateLatestQmlls()
{
// find latest qmlls, i.e. vals
if (!QtVersionManager::instance()->isLoaded())
return {};
const QtVersions versions = QtVersionManager::instance()->versions();
FilePath latestQmlls;
QVersionNumber latestVersion;
FilePath latestQmakeFilePath;
int latestUniqueId = std::numeric_limits<int>::min();
for (QtVersion *v : versions) {
// check if we find qmlls
QVersionNumber vNow = v->qtVersion();
FilePath qmllsNow = QmlJS::ModelManagerInterface::qmllsForBinPath(v->hostBinPath(), vNow);
if (!qmllsNow.isExecutableFile())
continue;
if (latestVersion > vNow)
continue;
FilePath qmakeNow = v->qmakeFilePath();
int uniqueIdNow = v->uniqueId();
if (latestVersion == vNow) {
if (latestQmakeFilePath > qmakeNow)
continue;
if (latestQmakeFilePath == qmakeNow && latestUniqueId >= v->uniqueId())
continue;
}
latestQmlls = qmllsNow;
latestQmakeFilePath = qmakeNow;
latestUniqueId = uniqueIdNow;
}
return latestQmlls;
}
QmllsSettingsManager *QmllsSettingsManager::instance()
{
static QmllsSettingsManager *manager = new QmllsSettingsManager;
return manager;
}
QmllsSettings QmllsSettingsManager::lastSettings()
{
QMutexLocker l(&m_mutex);
return m_lastSettings;
}
FilePath QmllsSettingsManager::latestQmlls()
{
QMutexLocker l(&m_mutex);
return m_latestQmlls;
}
void QmllsSettingsManager::setupAutoupdate()
{
QObject::connect(QtVersionManager::instance(),
&QtVersionManager::qtVersionsChanged,
this,
&QmllsSettingsManager::checkForChanges);
if (QtVersionManager::instance()->isLoaded())
checkForChanges();
else
QObject::connect(QtVersionManager::instance(),
&QtVersionManager::qtVersionsLoaded,
this,
&QmllsSettingsManager::checkForChanges);
}
void QmllsSettingsManager::checkForChanges()
{
FilePath newLatest = evaluateLatestQmlls();
QmllsSettings newSettings = QmlJsEditingSettings::get().qmllsSettigs();
if (m_lastSettings == newSettings && newLatest == m_latestQmlls)
return;
qCDebug(qmllsLog) << "qmlls settings changed:" << newSettings.useQmlls
<< newSettings.useLatestQmlls << newLatest;
{
QMutexLocker l(&m_mutex);
m_latestQmlls = newLatest;
m_lastSettings = newSettings;
}
emit settingsChanged();
}
} // namespace QmlJSEditor

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include "qmljseditor_global.h"
#include <utils/filepath.h>
#include <QMutex>
#include <QObject>
namespace QmlJSEditor {
struct QmllsSettings
{
bool useQmlls = true;
bool useLatestQmlls = false;
friend bool operator==(const QmllsSettings &s1, const QmllsSettings &s2)
{
return s1.useQmlls == s2.useQmlls && s1.useLatestQmlls == s2.useLatestQmlls;
}
friend bool operator!=(const QmllsSettings &s1, const QmllsSettings &s2) { return !(s1 == s2); }
};
class QMLJSEDITOR_EXPORT QmllsSettingsManager : public QObject
{
Q_OBJECT
public:
static QmllsSettingsManager *instance();
QmllsSettings lastSettings();
Utils::FilePath latestQmlls();
void setupAutoupdate();
public slots:
void checkForChanges();
signals:
void settingsChanged();
private:
QMutex m_mutex;
QmllsSettings m_lastSettings;
Utils::FilePath m_latestQmlls;
};
} // namespace QmlJSEditor

View File

@@ -169,9 +169,13 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
if (qtVersion && qtVersion->isValid()) { if (qtVersion && qtVersion->isValid()) {
projectInfo.tryQmlDump = project && qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT); projectInfo.tryQmlDump = project && qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT);
projectInfo.qtQmlPath = qtVersion->qmlPath(); projectInfo.qtQmlPath = qtVersion->qmlPath();
auto v = qtVersion->qtVersion();
projectInfo.qmllsPath = ModelManagerInterface::qmllsForBinPath(qtVersion->hostBinPath(), v);
projectInfo.qtVersionString = qtVersion->qtVersionString(); projectInfo.qtVersionString = qtVersion->qtVersionString();
} else if (!activeKit || !activeKit->value(QtSupport::SuppliesQtQuickImportPath::id(), false).toBool()) { } else if (!activeKit || !activeKit->value(QtSupport::SuppliesQtQuickImportPath::id(), false).toBool()) {
projectInfo.qtQmlPath = FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); projectInfo.qtQmlPath = FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath));
projectInfo.qmllsPath = ModelManagerInterface::qmllsForBinPath(
FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::BinariesPath)), QLibraryInfo::version());
projectInfo.qtVersionString = QLatin1String(qVersion()); projectInfo.qtVersionString = QLatin1String(qVersion());
} }

View File

@@ -212,12 +212,12 @@ void QmlBuildSystem::parseProject(RefreshOptions options)
if (auto modelManager = QmlJS::ModelManagerInterface::instance()) { if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
QStringList files = m_projectItem->files(); QStringList files = m_projectItem->files();
Utils::FilePaths filePaths(files.size()); modelManager
std::transform(files.cbegin(), ->updateSourceFiles(Utils::transform(files,
files.cend(), [](const QString &p) {
filePaths.begin(), return Utils::FilePath::fromString(p);
[](const QString &p) { return Utils::FilePath::fromString(p); }); }),
modelManager->updateSourceFiles(filePaths, true); true);
} }
QString mainFilePath = m_projectItem->mainFile(); QString mainFilePath = m_projectItem->mainFile();
if (!mainFilePath.isEmpty()) { if (!mainFilePath.isEmpty()) {
@@ -504,12 +504,10 @@ void QmlBuildSystem::refreshFiles(const QSet<QString> &/*added*/, const QSet<QSt
refresh(Files); refresh(Files);
if (!removed.isEmpty()) { if (!removed.isEmpty()) {
if (auto modelManager = QmlJS::ModelManagerInterface::instance()) { if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
Utils::FilePaths pathsRemoved(removed.size()); modelManager->removeFiles(
std::transform(removed.cbegin(), Utils::transform<QList<Utils::FilePath>>(removed, [](const QString &s) {
removed.cend(), return Utils::FilePath::fromString(s);
pathsRemoved.begin(), }));
[](const QString &s) { return Utils::FilePath::fromString(s); });
modelManager->removeFiles(pathsRemoved);
} }
} }
refreshTargetDirectory(); refreshTargetDirectory();
@@ -797,4 +795,3 @@ bool QmlBuildSystem::renameFile(Node * context, const FilePath &oldFilePath, con
} }
} // namespace QmlProjectManager } // namespace QmlProjectManager