9#include <QtCore/qfileinfo.h>
10#include <QtCore/qdir.h>
11#include <QtCore/qthreadpool.h>
12#include <QtCore/qlibraryinfo.h>
13#include <QtCore/qprocess.h>
14#include <QtCore/qdiriterator.h>
15#include <QtQmlDom/private/qqmldomtop_p.h>
108 m_cmakeStatus = DoesNotHaveCMake;
120 m_state = State::Stopping;
121 m_openDocumentsToUpdate.
clear();
122 shouldWait = m_nIndexInProgress != 0 || m_nUpdateInProgress != 0;
135int QQmlCodeModel::indexEvalProgress()
const
138 const int dirCost = 10;
141 costToDo += dirCost *
el.leftDepth;
142 costToDo += m_indexInProgressCost;
143 return m_indexDoneCost * 100 / (costToDo + m_indexDoneCost);
146void QQmlCodeModel::indexStart()
149 qCDebug(codeModelLog) <<
"indexStart";
152void QQmlCodeModel::indexEnd()
155 qCDebug(codeModelLog) <<
"indexEnd";
156 m_lastIndexProgress = 0;
157 m_nIndexInProgress = 0;
159 m_indexInProgressCost = 0;
163void QQmlCodeModel::indexSendProgress(
int progress)
165 if (progress <= m_lastIndexProgress)
167 m_lastIndexProgress = progress;
171bool QQmlCodeModel::indexCancelled()
174 if (m_state == State::Stopping)
179void QQmlCodeModel::indexDirectory(
const QString &
path,
int depthLeft)
181 if (indexCancelled())
188 addDirectory(
dir.filePath(
child), --depthLeft);
195 m_indexInProgressCost += qmljs.size();
196 progress = indexEvalProgress();
198 indexSendProgress(progress);
203 if (indexCancelled())
208 if (!fileToLoad.canonicalPath().isEmpty()) {
209 newCurrentPtr->loadBuiltins();
210 newCurrentPtr->loadFile(fileToLoad, [](Path,
const DomItem &,
const DomItem &) {});
211 newCurrentPtr->loadPendingDependencies();
217 --m_indexInProgressCost;
218 progress = indexEvalProgress();
220 indexSendProgress(progress);
228 const int maxDepth = 5;
230 addDirectory(
path, maxDepth);
234void QQmlCodeModel::addDirectory(
const QString &
path,
int depthLeft)
240 for (
auto it = m_toIndex.begin();
it != m_toIndex.end();) {
241 if (
it->path.startsWith(
path)) {
244 if (
it->path.at(
path.size()) == u
'/') {
245 it = m_toIndex.erase(
it);
252 m_toIndex.append({
path, depthLeft });
261 return p.startsWith(
path) && (
p.size() ==
path.size() ||
p.at(
path.size()) == u
'/');
263 auto it = m_toIndex.begin();
264 auto end = m_toIndex.end();
266 if (toRemove(
it->path))
267 it = m_toIndex.erase(
it);
273 validEnvPtr->removePath(
path);
275 currentEnvPtr->removePath(
path);
289 QString cPath =
f.canonicalFilePath();
291 cPath =
f.filePath();
294 if (!
res.isEmpty() &&
res != cPath)
306 auto &openDoc = m_openDocuments[
url];
307 if (!openDoc.textDocument)
308 openDoc.textDocument = std::make_shared<Utils::TextDocument>();
310 openDoc.textDocument->setVersion(version);
311 openDoc.textDocument->setPlainText(docText);
320 return m_openDocuments.value(
url);
337 const int maxIndexThreads = 1;
340 if (m_toIndex.isEmpty() || m_nIndexInProgress >= maxIndexThreads)
342 if (++m_nIndexInProgress == 1)
346 while (indexSome()) { }
350bool QQmlCodeModel::indexSome()
352 qCDebug(codeModelLog) <<
"indexSome";
356 if (m_toIndex.isEmpty()) {
357 if (--m_nIndexInProgress == 0)
362 m_toIndex.removeLast();
364 bool hasMore =
false;
368 if (m_toIndex.isEmpty()) {
369 if (--m_nIndexInProgress == 0)
383 qCDebug(codeModelLog) <<
"openNeedUpdate";
384 const int maxIndexThreads = 1;
387 if (m_openDocumentsToUpdate.
isEmpty() || m_nUpdateInProgress >= maxIndexThreads)
389 if (++m_nUpdateInProgress == 1)
393 while (openUpdateSome()) { }
397bool QQmlCodeModel::openUpdateSome()
399 qCDebug(codeModelLog) <<
"openUpdateSome start";
403 if (m_openDocumentsToUpdate.
isEmpty()) {
404 if (--m_nUpdateInProgress == 0)
408 auto it = m_openDocumentsToUpdate.
find(m_lastOpenDocumentUpdated);
409 auto end = m_openDocumentsToUpdate.
end();
411 it = m_openDocumentsToUpdate.
begin();
412 else if (++
it ==
end)
413 it = m_openDocumentsToUpdate.
begin();
415 m_openDocumentsToUpdate.
erase(
it);
417 bool hasMore =
false;
421 if (m_openDocumentsToUpdate.
isEmpty()) {
422 if (--m_nUpdateInProgress == 0)
429 openUpdate(toUpdate);
434void QQmlCodeModel::openUpdateStart()
436 qCDebug(codeModelLog) <<
"openUpdateStart";
439void QQmlCodeModel::openUpdateEnd()
441 qCDebug(codeModelLog) <<
"openUpdateEnd";
448void QQmlCodeModel::initializeCMakeStatus(
const QString &pathForSettings)
451 const QString cmakeCalls = u
"no-cmake-calls"_s;
452 m_settings->
search(pathForSettings);
453 if (m_settings->
isSet(cmakeCalls) && m_settings->
value(cmakeCalls).
toBool()) {
454 qWarning() <<
"Disabling CMake calls via .qmlls.ini setting.";
455 m_cmakeStatus = DoesNotHaveCMake;
461 process.setProgram(u
"cmake"_s);
462 process.setArguments({ u
"--version"_s });
464 process.waitForFinished();
465 m_cmakeStatus = process.exitCode() == 0 ? HasCMake : DoesNotHaveCMake;
467 if (m_cmakeStatus == DoesNotHaveCMake) {
468 qWarning() <<
"Disabling CMake calls because CMake was not found.";
473 &QQmlCodeModel::onCppFileChanged);
488bool QQmlCodeModel::callCMakeBuild(
const QStringList &buildPaths)
491 for (
const auto &
path : buildPaths) {
497 process.setProgram(command.first);
498 process.setArguments(command.second);
499 qCDebug(codeModelLog) <<
"Running" << process.program() << process.arguments();
503 success &= process.waitForFinished();
504 success &= (process.exitCode() == 0);
505 qCDebug(codeModelLog) << process.program() << process.arguments() <<
"terminated with"
506 << process.exitCode();
521 for (
const auto &rootUrl : m_rootUrls) {
527 qCDebug(codeModelLog) <<
"Searching for files to watch in workspace folder" << rootDir;
529 while (
it.hasNext()) {
548 auto resolver =
file->typeResolver();
552 auto types = resolver->importedTypes();
575void QQmlCodeModel::addFileWatches(
const DomItem &qmlFile)
579 const auto unwatchedPaths = m_cppFileWatcher.
addPaths(filepathsToWatch);
580 if (!unwatchedPaths.isEmpty()) {
581 qCDebug(codeModelLog) <<
"Cannot watch paths" << unwatchedPaths <<
"from requested"
586void QQmlCodeModel::onCppFileChanged(
const QString &)
588 m_rebuildRequired =
true;
593 qCDebug(codeModelLog) <<
"updating doc" <<
url <<
"to version" << version <<
"("
594 << docText.size() <<
"chars)";
597 if (m_cmakeStatus == RequiresInitialization)
598 initializeCMakeStatus(fPath);
603 if (m_cmakeStatus == HasCMake && !loadPaths.isEmpty() && m_rebuildRequired) {
604 callCMakeBuild(loadPaths);
605 m_rebuildRequired =
false;
608 loadPaths.append(m_importPaths);
609 if (std::shared_ptr<DomEnvironment> newCurrentPtr = newCurrent.ownerAs<
DomEnvironment>()) {
610 newCurrentPtr->setLoadPaths(loadPaths);
617 p =
file.canonicalPath();
618 if (m_cmakeStatus == HasCMake)
619 addFileWatches(
file);
621 newCurrentPtr->loadPendingDependencies();
636 <<
"docUpdate: version" << version <<
"of document"
645 qCWarning(lspServerLog) <<
"skipping update of current doc to obsolete version"
648 if (
item.field(Fields::isValid).value().toBool(
false)) {
654 qCWarning(lspServerLog) <<
"skippig update of valid doc to obsolete version"
659 <<
"avoid update of validDoc to " << version <<
"of document"
664 if (codeModelLog().isDebugEnabled()) {
665 qCDebug(codeModelLog) <<
"finished update doc of " <<
url <<
"to version" << version;
676 m_openDocuments.remove(
url);
710 return m_buildPathsForRootUrl.
value(
url);
720 QList<QByteArray> roots;
723 roots = m_buildPathsForRootUrl.
keys();
727 if (el1.size() > el2.size())
729 if (el1.size() < el2.size())
735 if (!roots.isEmpty() && roots.last().isEmpty())
738 if (!urlSlash.isEmpty() &&
isNotSeparator(urlSlash.at(urlSlash.size() - 1)))
739 urlSlash.append(
'/');
742 if (urlSlash.startsWith(root)) {
751 if (buildPaths.isEmpty()) {
756 if (buildPaths.isEmpty()) {
759 buildPaths += envPaths;
764 if (buildPaths.isEmpty() && m_settings) {
767 if (m_settings->
isSet(buildDir))
773 if (buildPaths.isEmpty()) {
776 const int maxDirDepth = 8;
777 int iDir = maxDirDepth;
780 while (
d.cdUp() && --iDir > 0) {
782 if (fInfo.completeBaseName() == u
"build"
783 || fInfo.completeBaseName().startsWith(u
"build-%1"_s.arg(dirName))) {
786 if (!lastModified.
isValid() || lastModified < fInfo.lastModified()) {
788 buildPaths.append(fInfo.absoluteFilePath());
796 std::reverse(buildPaths.begin(), buildPaths.end());
797 const int maxDeps = 4;
798 while (!buildPaths.isEmpty()) {
802 if (
QFile::exists(bPath + u
"/_deps") && bPath.split(u
"/_deps/"_s).size() < maxDeps) {
803 QDir d(bPath + u
"/_deps");
805 buildPaths.append(fInfo.absoluteFilePath());
824 bool updateDoc =
false;
825 bool updateScope =
false;
826 std::optional<int> rNow = 0;
829 std::shared_ptr<Utils::TextDocument> document;
838 rNow = document->version();
873 dbg.noquote().nospace() <<
"{";
877 dbg <<
" doc: ------------\n"
885 dbg <<
" validDocVersion:"
888 dbg <<
" validDoc: ------------\n"
QString toString(const QString &defaultValue={}) const
Returns the string value stored in this QCborValue, if it is of the string type.
\inmodule QtCore\reentrant
bool isValid() const
Returns true if this datetime represents a definite moment, otherwise false.
The QDirIterator class provides an iterator for directory entrylists.
static constexpr QChar listSeparator() noexcept
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
void fileChanged(const QString &path, QPrivateSignal)
This signal is emitted when the file at the specified path is modified, renamed or removed from disk.
QStringList files() const
Returns a list of paths to files that are being watched.
QStringList removePaths(const QStringList &files)
Removes the specified paths from the file system watcher.
QStringList addPaths(const QStringList &files)
Adds each path in paths to the file system watcher.
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool remove(const Key &key)
Removes the item that has the key from the hash.
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
T value(const Key &key) const noexcept
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Implements a server for the language server protocol.
bool removeOne(const AT &t)
void append(parameter_type t)
bool tryLock(int timeout=0) noexcept
Attempts to lock the mutex.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Represents a consistent set of types organized in modules, it is the top level of the DOM.
void loadFile(const FileToLoad &file, const Callback &callback, std::optional< DomType > fileType=std::optional< DomType >(), const ErrorHandler &h=nullptr)
std::shared_ptr< T > ownerAs() const
DomItem field(QStringView name) const
DomItem path(const Path &p, const ErrorHandler &h=&defaultErrorHandler) const
MutableDomItem makeCopy(CopyOption option=CopyOption::EnvConnected) const
static FileToLoad fromFileSystem(const std::weak_ptr< DomEnvironment > &environment, const QString &canonicalPath)
static FileToLoad fromMemory(const std::weak_ptr< DomEnvironment > &environment, const QString &path, const QString &data)
A QmlFile, when loaded in a DomEnvironment that has the DomCreationOption::WithSemanticAnalysis,...
static QPair< QString, QStringList > cmakeBuildCommand(const QString &path)
iterator erase(const_iterator i)
iterator find(const T &value)
iterator insert(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
qsizetype size() const noexcept
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString last(qsizetype n) const &
static QThreadPool * globalInstance()
Returns the global QThreadPool instance.
static void yieldCurrentThread()
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
bool toBool() const
Returns the variant as a bool if the variant has userType() Bool.
bool scopeDependenciesChanged
std::optional< int > scopeVersion
QDateTime scopeDependenciesLoadTime
std::optional< int > docVersion
std::optional< int > validDocVersion
QDebug dump(QDebug dbg, DumpOptions dump=DumpOption::NoCode)
QQmlJS::Dom::DomItem validDoc
std::shared_ptr< Utils::TextDocument > textDocument
OpenDocumentSnapshot snapshot
void newOpenFile(const QByteArray &url, int version, const QString &docText)
void addRootUrls(const QList< QByteArray > &urls)
QList< QByteArray > rootUrls() const
QQmlCodeModel(QObject *parent=nullptr, QQmlToolingSettings *settings=nullptr)
void setBuildPathsForRootUrl(QByteArray url, const QStringList &paths)
OpenDocumentSnapshot snapshotByUrl(const QByteArray &url)
static QStringList fileNamesToWatch(const QQmlJS::Dom::DomItem &qmlFile)
void addOpenToUpdate(const QByteArray &)
QString url2Path(const QByteArray &url, UrlLookup options=UrlLookup::Caching)
OpenDocument openDocumentByUrl(const QByteArray &url)
QStringList findFilePathsFromFileNames(const QStringList &fileNames) const
QStringList buildPathsForFileUrl(const QByteArray &url)
void setRootUrls(const QList< QByteArray > &urls)
void removeDirectory(const QString &path)
void removeRootUrls(const QList< QByteArray > &urls)
void addDirectoriesToIndex(const QStringList &paths, QLanguageServer *server)
void newDocForOpenFile(const QByteArray &url, int version, const QString &docText)
void updatedSnapshot(const QByteArray &url)
QStringList buildPathsForRootUrl(const QByteArray &url)
void closeOpenFile(const QByteArray &url)
RegisteredSemanticTokens & registeredTokens()
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static bool isNotSeparator(char c)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall DBusPendingCall return DBusPendingCall return dbus_int32_t return DBusServer * server
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLsizei GLenum GLenum * types
GLsizei const GLuint * paths
GLsizei const GLchar *const * path
static bool isComposite(const QQmlJSScope::ConstPtr &scope)
#define QmlLSPluginInterface_iid
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
#define QStringLiteral(str)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
static uint toIndex(ExecutionEngine *e, const Value &v)
QSettings settings("MySoft", "Star Runner")
[0]
QUrl url("example.com")
[constructor-url-reference]
bool contains(const AT &t) const noexcept