From 61f0bf479dab9688c742ca061d2635c86d0f316c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 22 May 2023 16:28:45 +0200 Subject: [PATCH] FileSearch: Reuse searchInContents() inside findInFiles() Get rid of findInFilesRegExp(). Change-Id: Iae47b023a1428a66fff165c0a0a4fa38d55ba132 Reviewed-by: Eike Ziller --- src/libs/utils/filesearch.cpp | 237 ++--------------------- src/libs/utils/filesearch.h | 10 +- src/plugins/texteditor/basefilefind.cpp | 14 +- tests/auto/filesearch/tst_filesearch.cpp | 18 +- 4 files changed, 22 insertions(+), 257 deletions(-) diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 0fbb2ad9f3c..662448a7de3 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -12,7 +12,6 @@ #include "utilstr.h" #include -#include #include #include @@ -218,7 +217,6 @@ static inline QString msgFound(const QString &searchTerm, int numMatches, int nu namespace { -// returns success static bool getFileContent(const FilePath &filePath, QTextCodec *encoding, QString *tempString, @@ -239,57 +237,13 @@ static bool getFileContent(const FilePath &filePath, class FileSearch { public: - FileSearch(const QString &searchTerm, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap); void operator()(QFutureInterface &futureInterface, const FileIterator::Item &item) const; - -private: - QMap fileToContentsMap; - QString searchTermLower; - QString searchTermUpper; - int termMaxIndex; - const QChar *termData; - const QChar *termDataLower; - const QChar *termDataUpper; - bool caseSensitive; - bool wholeWord; + const QString m_searchTerm; + const FindFlags m_flags; + const QMap m_fileToContentsMap; }; -class FileSearchRegExp -{ -public: - FileSearchRegExp(const QString &searchTerm, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap); - FileSearchRegExp(const FileSearchRegExp &other); - void operator()(QFutureInterface &futureInterface, - const FileIterator::Item &item) const; - -private: - QRegularExpressionMatch doGuardedMatch(const QString &line, int offset) const; - - QMap fileToContentsMap; - QRegularExpression expression; - mutable QMutex mutex; -}; - -FileSearch::FileSearch(const QString &searchTerm, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap) -{ - this->fileToContentsMap = fileToContentsMap; - caseSensitive = (flags & QTextDocument::FindCaseSensitively); - wholeWord = (flags & QTextDocument::FindWholeWords); - searchTermLower = searchTerm.toLower(); - searchTermUpper = searchTerm.toUpper(); - termMaxIndex = searchTerm.length() - 1; - termData = searchTerm.constData(); - termDataLower = searchTermLower.constData(); - termDataUpper = searchTermUpper.constData(); -} - void FileSearch::operator()(QFutureInterface &futureInterface, const FileIterator::Item &item) const { @@ -298,169 +252,16 @@ void FileSearch::operator()(QFutureInterface &futureInterface qCDebug(searchLog) << "Searching in" << item.filePath; futureInterface.setProgressRange(0, 1); futureInterface.setProgressValue(0); - SearchResultItems results; - QString tempString; - if (!getFileContent(item.filePath, item.encoding, &tempString, fileToContentsMap)) { + QString contents; + if (!getFileContent(item.filePath, item.encoding, &contents, m_fileToContentsMap)) { qCDebug(searchLog) << "- failed to get content for" << item.filePath; futureInterface.cancel(); // failure return; } - QTextStream stream(&tempString); - int lineNr = 0; - while (!stream.atEnd()) { - ++lineNr; - const QString chunk = stream.readLine(); - const int chunkLength = chunk.length(); - const QChar *chunkPtr = chunk.constData(); - const QChar *chunkEnd = chunkPtr + chunkLength - 1; - for (const QChar *regionPtr = chunkPtr; regionPtr + termMaxIndex <= chunkEnd; ++regionPtr) { - const QChar *regionEnd = regionPtr + termMaxIndex; - if ( /* optimization check for start and end of region */ - // case sensitive - (caseSensitive && *regionPtr == termData[0] - && *regionEnd == termData[termMaxIndex]) - || - // case insensitive - (!caseSensitive && (*regionPtr == termDataLower[0] - || *regionPtr == termDataUpper[0]) - && (*regionEnd == termDataLower[termMaxIndex] - || *regionEnd == termDataUpper[termMaxIndex])) - ) { - bool equal = true; - - // whole word check - const QChar *beforeRegion = regionPtr - 1; - const QChar *afterRegion = regionEnd + 1; - if (wholeWord - && (((beforeRegion >= chunkPtr) - && (beforeRegion->isLetterOrNumber() - || ((*beforeRegion) == QLatin1Char('_')))) - || - ((afterRegion <= chunkEnd) - && (afterRegion->isLetterOrNumber() - || ((*afterRegion) == QLatin1Char('_')))) - )) { - equal = false; - } else { - // check all chars - int regionIndex = 1; - for (const QChar *regionCursor = regionPtr + 1; - regionCursor < regionEnd; - ++regionCursor, ++regionIndex) { - if ( // case sensitive - (caseSensitive - && *regionCursor != termData[regionIndex]) - || - // case insensitive - (!caseSensitive - && *regionCursor != termDataLower[regionIndex] - && *regionCursor != termDataUpper[regionIndex]) - ) { - equal = false; - break; - } - } - } - if (equal) { - SearchResultItem result; - result.setFilePath(item.filePath); - result.setMainRange(lineNr, regionPtr - chunkPtr, termMaxIndex + 1); - result.setDisplayText(clippedText(chunk, MAX_LINE_SIZE)); - result.setUserData(QStringList()); - result.setUseTextEditorFont(true); - results << result; - regionPtr += termMaxIndex; // another +1 done by for-loop - } - } - } - if (futureInterface.isPaused()) - futureInterface.waitForResume(); - if (futureInterface.isCanceled()) - break; - } - if (!futureInterface.isCanceled()) { - futureInterface.reportResult(results); - futureInterface.setProgressValue(1); - } - qCDebug(searchLog) << "- finished searching in" << item.filePath; -} - -FileSearchRegExp::FileSearchRegExp(const QString &searchTerm, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap) -{ - this->fileToContentsMap = fileToContentsMap; - QString term = searchTerm; - if (flags & QTextDocument::FindWholeWords) - term = QString::fromLatin1("\\b%1\\b").arg(term); - const QRegularExpression::PatternOptions patternOptions = (flags & QTextDocument::FindCaseSensitively) - ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption; - expression = QRegularExpression(term, patternOptions); -} - -FileSearchRegExp::FileSearchRegExp(const FileSearchRegExp &other) - : fileToContentsMap(other.fileToContentsMap), - expression(other.expression) -{ -} - -QRegularExpressionMatch FileSearchRegExp::doGuardedMatch(const QString &line, int offset) const -{ - QMutexLocker lock(&mutex); - return expression.match(line, offset); -} - -void FileSearchRegExp::operator()(QFutureInterface &futureInterface, - const FileIterator::Item &item) const -{ - if (!expression.isValid()) { - futureInterface.cancel(); - return; - } - if (futureInterface.isCanceled()) - return; - qCDebug(searchLog) << "Searching in" << item.filePath; - futureInterface.setProgressRange(0, 1); - futureInterface.setProgressValue(0); - SearchResultItems results; - QString tempString; - if (!getFileContent(item.filePath, item.encoding, &tempString, fileToContentsMap)) { - qCDebug(searchLog) << "- failed to get content for" << item.filePath; - futureInterface.cancel(); // failure - return; - } - QTextStream stream(&tempString); - int lineNr = 0; - - QString line; - QRegularExpressionMatch match; - while (!stream.atEnd()) { - ++lineNr; - line = stream.readLine(); - const QString resultItemText = clippedText(line, MAX_LINE_SIZE); - int lengthOfLine = line.size(); - int pos = 0; - while ((match = doGuardedMatch(line, pos)).hasMatch()) { - pos = match.capturedStart(); - SearchResultItem result; - result.setFilePath(item.filePath); - result.setMainRange(lineNr, pos, match.capturedLength()); - result.setDisplayText(resultItemText); - result.setUserData(match.capturedTexts()); - result.setUseTextEditorFont(true); - results << result; - if (match.capturedLength() == 0) - break; - pos += match.capturedLength(); - if (pos >= lengthOfLine) - break; - } - if (futureInterface.isPaused()) - futureInterface.waitForResume(); - if (futureInterface.isCanceled()) - break; - } + const QFuture future(futureInterface.future()); + const SearchResultItems results = searchInContents(future, m_searchTerm, m_flags, item.filePath, + contents); if (!futureInterface.isCanceled()) { futureInterface.reportResult(results); futureInterface.setProgressValue(1); @@ -530,31 +331,15 @@ void cleanUpFileSearch(QFutureInterface &futureInterface, } // namespace -QFuture Utils::findInFiles(const QString &searchTerm, - FileIterator *files, - QTextDocument::FindFlags flags, +QFuture Utils::findInFiles(const QString &searchTerm, FileIterator *files, + FindFlags flags, const QMap &fileToContentsMap) { return mapReduce(files->begin(), files->end(), [searchTerm, files](QFutureInterface &futureInterface) { return initFileSearch(futureInterface, searchTerm, files); }, - FileSearch(searchTerm, flags, fileToContentsMap), - &collectSearchResults, - &cleanUpFileSearch); -} - -QFuture Utils::findInFilesRegExp( - const QString &searchTerm, - FileIterator *files, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap) -{ - return mapReduce(files->begin(), files->end(), - [searchTerm, files](QFutureInterface &futureInterface) { - return initFileSearch(futureInterface, searchTerm, files); - }, - FileSearchRegExp(searchTerm, flags, fileToContentsMap), + FileSearch{searchTerm, flags, fileToContentsMap}, &collectSearchResults, &cleanUpFileSearch); } diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h index 664ccf02319..b0bd01c3362 100644 --- a/src/libs/utils/filesearch.h +++ b/src/libs/utils/filesearch.h @@ -171,15 +171,7 @@ private: }; QTCREATOR_UTILS_EXPORT QFuture findInFiles(const QString &searchTerm, - FileIterator *files, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap = {}); - -QTCREATOR_UTILS_EXPORT QFuture findInFilesRegExp( - const QString &searchTerm, - FileIterator *files, - QTextDocument::FindFlags flags, - const QMap &fileToContentsMap = {}); + FileIterator *files, FindFlags flags, const QMap &fileToContentsMap); QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts); diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 2561bcfeb36..a98cd210826 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -54,14 +54,12 @@ public: QFuture executeSearch(const TextEditor::FileFindParameters ¶meters, BaseFileFind *baseFileFind) override { - const auto func = parameters.flags & FindRegularExpression ? Utils::findInFilesRegExp - : Utils::findInFiles; - - return func(parameters.text, - baseFileFind->files(parameters.nameFilters, parameters.exclusionFilters, - parameters.additionalParameters), - Utils::textDocumentFlagsForFindFlags(parameters.flags), - TextDocument::openedTextDocumentContents()); + return Utils::findInFiles(parameters.text, + baseFileFind->files(parameters.nameFilters, + parameters.exclusionFilters, + parameters.additionalParameters), + parameters.flags, + TextDocument::openedTextDocumentContents()); } Core::IEditor *openEditor(const SearchResultItem &/*item*/, diff --git a/tests/auto/filesearch/tst_filesearch.cpp b/tests/auto/filesearch/tst_filesearch.cpp index 95bec53e099..e4ce57b670f 100644 --- a/tests/auto/filesearch/tst_filesearch.cpp +++ b/tests/auto/filesearch/tst_filesearch.cpp @@ -11,12 +11,6 @@ using namespace Utils; class tst_FileSearch : public QObject { Q_OBJECT -public: - enum RegExpFlag { - NoRegExp, - RegExp - }; - private slots: void multipleResults(); void caseSensitive(); @@ -41,16 +35,12 @@ SearchResultItem searchResult(const FilePath &fileName, const QString &matchingL } void test_helper(const FilePath &filePath, const SearchResultItems &expectedResults, - const QString &term, QTextDocument::FindFlags flags = {}, - tst_FileSearch::RegExpFlag regexp = tst_FileSearch::NoRegExp) + const QString &term, Utils::FindFlags flags = {}) { FileIterator *it = new FileListIterator({filePath}, {QTextCodec::codecForLocale()}); QFutureWatcher watcher; QSignalSpy ready(&watcher, &QFutureWatcherBase::resultsReadyAt); - if (regexp == tst_FileSearch::NoRegExp) - watcher.setFuture(Utils::findInFiles(term, it, flags)); - else - watcher.setFuture(Utils::findInFilesRegExp(term, it, flags)); + watcher.setFuture(Utils::findInFiles(term, it, flags, {})); watcher.future().waitForFinished(); QTest::qWait(100); // process events QCOMPARE(ready.count(), 1); @@ -84,7 +74,7 @@ void tst_FileSearch::multipleResults() expectedResults << searchResult(m_filePath, "aaaaaaaa this line has 2 results for four a in a row", 5, 4, 4, {"aaaa"}); - test_helper(m_filePath, expectedResults, "aaaa", {}, RegExp); + test_helper(m_filePath, expectedResults, "aaaa", FindRegularExpression); } void tst_FileSearch::caseSensitive() @@ -92,7 +82,7 @@ void tst_FileSearch::caseSensitive() SearchResultItems expectedResults; expectedResults << searchResult(m_filePath, "search CaseSensitively for casesensitive", 3, 7, 13); - test_helper(m_filePath, expectedResults, "CaseSensitive", QTextDocument::FindCaseSensitively); + test_helper(m_filePath, expectedResults, "CaseSensitive", FindCaseSensitively); } void tst_FileSearch::caseInSensitive()