File indexing completed on 2024-04-28 05:49:12
0001 /* 0002 SPDX-FileCopyrightText: 2011-21 Kåre Särs <kare.sars@iki.fi> 0003 SPDX-FileCopyrightText: 2021 Christoph Cullmann <cullmann@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #pragma once 0009 0010 // Qt 0011 #include <QMutex> 0012 #include <QMutexLocker> 0013 #include <QObject> 0014 #include <QRegularExpression> 0015 #include <QRunnable> 0016 #include <QStringList> 0017 0018 // std 0019 #include <atomic> 0020 0021 // locals 0022 #include "MatchModel.h" 0023 0024 class QString; 0025 class QUrl; 0026 class QFile; 0027 0028 /** 0029 * Thread-safe worklist to feed the SearchDiskFiles runnables. 0030 */ 0031 class SearchDiskFilesWorkList 0032 { 0033 public: 0034 /** 0035 * Default constructor => nothing to be done 0036 */ 0037 SearchDiskFilesWorkList() = default; 0038 0039 /** 0040 * Any workers running? 0041 * @return any worker running? 0042 */ 0043 bool isRunning() 0044 { 0045 QMutexLocker lock(&m_mutex); 0046 return m_currentRunningRunnables > 0; 0047 } 0048 0049 /** 0050 * Search canceled? 0051 * @return canceled? 0052 */ 0053 bool isCanceled() 0054 { 0055 return m_canceled; 0056 } 0057 0058 /** 0059 * Init the search, shall only be done if not running. 0060 * @param files files to search 0061 * @param numberOfWorkers number of workers we will spawn 0062 */ 0063 void init(const QStringList &files, int numberOfWorkers) 0064 { 0065 /** 0066 * ensure sane initial state: last search is done! 0067 * should hold even if canceled, the last markOnRunnableAsDone clears all fields! 0068 */ 0069 QMutexLocker lock(&m_mutex); 0070 Q_ASSERT(m_currentRunningRunnables == 0); 0071 Q_ASSERT(m_filesToSearch.isEmpty()); 0072 Q_ASSERT(m_filesToSearchIndex == 0); 0073 0074 /** 0075 * we shall not be called without any work! 0076 */ 0077 Q_ASSERT(!files.isEmpty()); 0078 Q_ASSERT(numberOfWorkers > 0); 0079 0080 /** 0081 * init work 0082 */ 0083 m_currentRunningRunnables = numberOfWorkers; 0084 m_filesToSearch = files; 0085 m_filesToSearchIndex = 0; 0086 m_canceled = false; 0087 } 0088 0089 /** 0090 * Get one file to search if still some there. 0091 * Will return empty string if no further work (or canceled) 0092 * @return file to search next or empty string 0093 */ 0094 QString nextFileToSearch() 0095 { 0096 QMutexLocker lock(&m_mutex); 0097 if (m_filesToSearchIndex >= m_filesToSearch.size()) { 0098 return QString(); 0099 } 0100 0101 // else return file, shall not be empty and advance one file 0102 const auto file = m_filesToSearch.at(m_filesToSearchIndex); 0103 Q_ASSERT(!file.isEmpty()); 0104 ++m_filesToSearchIndex; 0105 return file; 0106 } 0107 0108 /** 0109 * Mark one runnable as done. 0110 */ 0111 void markOnRunnableAsDone() 0112 { 0113 QMutexLocker lock(&m_mutex); 0114 Q_ASSERT(m_currentRunningRunnables > 0); 0115 --m_currentRunningRunnables; 0116 0117 // if we are done, cleanup 0118 if (m_currentRunningRunnables == 0) { 0119 m_filesToSearch.clear(); 0120 m_filesToSearchIndex = 0; 0121 } 0122 } 0123 0124 /** 0125 * Cancel the work. 0126 */ 0127 void cancel() 0128 { 0129 QMutexLocker lock(&m_mutex); 0130 m_canceled = true; 0131 m_filesToSearch.clear(); 0132 m_filesToSearchIndex = 0; 0133 } 0134 0135 private: 0136 /** 0137 * non-recursive mutex to lock internals, only locked a very short time 0138 */ 0139 QMutex m_mutex; 0140 0141 /** 0142 * current number of still active runnables, if == 0 => nothing running 0143 */ 0144 int m_currentRunningRunnables{0}; // guarded by m_mutex 0145 0146 /** 0147 * worklist => files to search in on the disk 0148 */ 0149 QStringList m_filesToSearch; // guarded by m_mutex 0150 0151 /** 0152 * current index into the worklist => next file to search 0153 * we don't do modify the stringlist, we just move the index 0154 */ 0155 int m_filesToSearchIndex{0}; // guarded by m_mutex 0156 0157 /** 0158 * was the search canceled? 0159 */ 0160 std::atomic_bool m_canceled{false}; 0161 }; 0162 0163 class SearchDiskFiles : public QObject, public QRunnable 0164 { 0165 Q_OBJECT 0166 0167 public: 0168 SearchDiskFiles(SearchDiskFilesWorkList &worklist, const QRegularExpression ®exp, const bool includeBinaryFiles); 0169 0170 void run() override; 0171 0172 Q_SIGNALS: 0173 void matchesFound(const QUrl &url, const QList<KateSearchMatch> &searchMatches, KTextEditor::Document *doc = nullptr); 0174 0175 private: 0176 QList<KateSearchMatch> searchSingleLineRegExp(QFile &file); 0177 QList<KateSearchMatch> searchMultiLineRegExp(QFile &file); 0178 0179 private: 0180 SearchDiskFilesWorkList &m_worklist; 0181 const QRegularExpression m_regExp; 0182 bool m_includeBinaryFiles = false; 0183 };