File indexing completed on 2024-05-12 04:37:42

0001 /*
0002     SPDX-FileCopyrightText: 2006 Adam Treat <treat@kde.org>
0003     SPDX-FileCopyrightText: 2007 Kris Wong <kris.p.wong@gmail.com>
0004     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef KDEVPLATFORM_BACKGROUNDPARSER_H
0010 #define KDEVPLATFORM_BACKGROUNDPARSER_H
0011 
0012 #include <language/languageexport.h>
0013 #include <interfaces/istatus.h>
0014 #include <language/duchain/topducontext.h>
0015 #include <language/interfaces/ilanguagesupport.h>
0016 #include "parsejob.h"
0017 
0018 namespace ThreadWeaver {
0019 class Job;
0020 class QObjectDecorator;
0021 class Weaver;
0022 }
0023 
0024 namespace KDevelop {
0025 class DocumentChangeTracker;
0026 
0027 class IDocument;
0028 class IProject;
0029 class ILanguageController;
0030 class ParserDependencyPolicy;
0031 
0032 /**
0033  * This class handles the creation of parse jobs for given file URLs.
0034  *
0035  * For performance reasons you must always use clean, canonical URLs. If you do not do that,
0036  * issues might arise (and the debug build will assert).
0037  */
0038 class KDEVPLATFORMLANGUAGE_EXPORT BackgroundParser
0039     : public QObject
0040     , public IStatus
0041 {
0042     Q_OBJECT
0043     Q_INTERFACES(KDevelop::IStatus)
0044 
0045 public:
0046     explicit BackgroundParser(ILanguageController* languageController);
0047     ~BackgroundParser() override;
0048 
0049     QString statusName() const override;
0050 
0051     enum {
0052         BestPriority = -10000,  ///Best possible job-priority. No jobs should actually have this.
0053         NormalPriority = 0,     ///Standard job-priority. This priority is used for parse-jobs caused by document-editing/opening.
0054         ///There is an additional parsing-thread reserved for jobs with this and better priority, to improve responsiveness.
0055         InitialParsePriority = 10000, ///Priority used when adding file on project loading
0056         WorstPriority = 100000  ///Worst possible job-priority.
0057     };
0058 
0059     /**
0060      * Queries the background parser as to whether there is currently
0061      * a parse job for @p document, and if so, returns it.
0062      *
0063      * This may not contain all of the parse jobs that are intended
0064      * unless you call in from your job's ThreadWeaver::Job::aboutToBeQueued()
0065      * function.
0066      */
0067     ParseJob* parseJobForDocument(const IndexedString& document) const;
0068 
0069     /**
0070      * Set how many ThreadWeaver threads the background parser should set up and use.
0071      */
0072     void setThreadCount(int threadCount);
0073 
0074     /**
0075      * Return how many ThreadWeaver threads the background parser should set up and use.
0076      */
0077     int threadCount() const;
0078 
0079     /**
0080      * Set the delay in milliseconds before the background parser starts parsing.
0081      */
0082     void setDelay(int milliseconds);
0083 
0084     /**
0085      * Returns all documents that were added through addManagedTopRange. This is typically the currently
0086      * open documents.
0087      */
0088     QList<IndexedString> managedDocuments();
0089 
0090     /**
0091      * Returns the tracker for the given url if the document is being tracked, else returns zero.
0092      * This function is thread-safe, but the returned object also isn't, so you must not use it
0093      * when you're in a background thread without the foreground lock acquired.
0094      * */
0095     DocumentChangeTracker* trackerForUrl(const IndexedString& url) const;
0096 
0097     bool waitForIdle() const;
0098 
0099 Q_SIGNALS:
0100     /**
0101      * Emitted whenever a document parse-job has finished.
0102      * The job contains the du-chain(if one was created) etc.
0103      *
0104      * The job is deleted after this signal has been emitted.  Receivers should not hold
0105      * references to it.
0106      *
0107      * Note that if you want to be get updated for all DUChain updates, use
0108      * DUChain::updateReady instead, as a single ParseJob may update multiple
0109      * DUChain top contexts.
0110      *
0111      * @sa DUChain::updateReady
0112      */
0113     void parseJobFinished(KDevelop::ParseJob* job);
0114 
0115     // Implementations of IStatus signals
0116     void clearMessage(KDevelop::IStatus*) override;
0117     void showMessage(KDevelop::IStatus*, const QString& message, int timeout = 0) override;
0118     void hideProgress(KDevelop::IStatus*) override;
0119     void showProgress(KDevelop::IStatus*, int minimum, int maximum, int value) override;
0120     void showErrorMessage(const QString&, int) override;
0121 
0122 public Q_SLOTS:
0123     /**
0124      * Aborts all parse jobs
0125      */
0126     void abortAllJobs();
0127 
0128     /**
0129      * Suspends execution of the background parser
0130      *
0131      * NOTE: Only the Core should call this
0132      */
0133     void suspend();
0134 
0135     /**
0136      * Resumes execution of the background parser
0137      *
0138      * NOTE: Only the Core should call this
0139      */
0140     void resume();
0141 
0142     /// Reverts all requests that were made for the given notification-target.
0143     /// priorities and requested features will be reverted as well.
0144     void revertAllRequests(QObject* notifyWhenReady);
0145 
0146     /**
0147      * Queues up the @p url to be parsed.
0148      * @p features The minimum features that should be computed for this top-context
0149      * @p priority A value that manages the order of parsing. Documents with lowest priority are parsed first.
0150      * @param notifyWhenReady An optional pointer to a QObject that should contain a slot
0151      *                        "void updateReady(KDevelop::IndexedString url, KDevelop::ReferencedTopDUContext topContext)".
0152      *                        The notification is guaranteed to be called once for each call to addDocument. The given top-context
0153      *                        may be invalid if the update failed.
0154      * @param flags Flags indicating how the document should be treated in the queue
0155      * @param delay_ms The delay in milliseconds to add the job with, or one of the values of the
0156      *                 ILanguageSupport::ReparseDelaySpecialValues enum.
0157      */
0158     void addDocument(const IndexedString& url,
0159                      TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts,
0160                      int priority = 0,
0161                      QObject* notifyWhenReady = nullptr,
0162                      ParseJob::SequentialProcessingFlags flags = ParseJob::IgnoresSequentialProcessing,
0163                      int delay_ms = ILanguageSupport::DefaultDelay);
0164 
0165     /**
0166      * try to add a listener to an existing document
0167      * @see addDocument(...) for parameter description
0168      * @returns true if the document existed and a listener was added
0169      */
0170     [[nodiscard]]
0171     bool addListenerToDocumentIfExist(const IndexedString& url,
0172                      TopDUContext::Features features = TopDUContext::VisibleDeclarationsAndContexts,
0173                      int priority = 0,
0174                      QObject* notifyWhenReady = nullptr,
0175                      ParseJob::SequentialProcessingFlags flags = ParseJob::IgnoresSequentialProcessing,
0176                      int delay_ms = ILanguageSupport::DefaultDelay);
0177 
0178     /**
0179      * Removes the @p url that is registered for the given notification from the url.
0180      *
0181      * @param notifyWhenReady Notifier the document was added with.
0182      */
0183     void removeDocument(const IndexedString& url, QObject* notifyWhenReady = nullptr);
0184 
0185     /**
0186      * Forces the current queue to be parsed.
0187      */
0188     void parseDocuments();
0189 
0190     void updateProgressData();
0191 
0192     /// Disables processing for all jobs that have a worse priority than @p priority
0193     /// This can be used to temporarily limit the processing to only the most important jobs.
0194     /// To only enable processing for important jobs, call setNeededPriority(0).
0195     /// This should only be used to temporarily alter the processing. A progress-bar
0196     /// will still be shown for the not yet processed jobs.
0197     void setNeededPriority(int priority);
0198     /// Disables all processing of new jobs, equivalent to setNeededPriority(BestPriority)
0199     void disableProcessing();
0200     /// Enables all processing of new jobs, equivalent to setNeededPriority(WorstPriority)
0201     void enableProcessing();
0202 
0203     /// Returns true if the given url is queued for parsing
0204     bool isQueued(const IndexedString& url) const;
0205 
0206     /// Retrieve the current priority for the given URL.
0207     /// You need to check whether @param url is queued before calling this function.
0208     int priorityForDocument(const IndexedString& url) const;
0209 
0210     /// Returns the number of queued jobs (not yet running nor submitted to ThreadWeaver)
0211     int queuedCount() const;
0212 
0213     /// Returns true if there are no jobs running nor queued anywhere
0214     bool isIdle() const;
0215 
0216     void documentClosed(KDevelop::IDocument*);
0217     void documentLoaded(KDevelop::IDocument*);
0218     void documentUrlChanged(KDevelop::IDocument*);
0219 
0220     void loadSettings();
0221 
0222 protected Q_SLOTS:
0223     void parseComplete(const ThreadWeaver::JobPointer& job);
0224     void parseProgress(KDevelop::ParseJob*, float value, const QString& text);
0225     void startTimer(int delay);
0226     void aboutToQuit();
0227     void updateProgressBar();
0228 
0229 private:
0230     friend class BackgroundParserPrivate;
0231     class BackgroundParserPrivate* d_ptr;
0232     Q_DECLARE_PRIVATE(BackgroundParser)
0233 
0234 private Q_SLOTS:
0235     /// Tracking of projects in state of loading.
0236     void projectAboutToBeOpened(KDevelop::IProject* project);
0237     void projectOpened(KDevelop::IProject* project);
0238     void projectOpeningAborted(KDevelop::IProject* project);
0239 };
0240 }
0241 #endif