SilverSearcher: Reuse searchInProcessOutput()

Change-Id: Ifc28a88c7bd0de94ea78c5f3eaaa2179b0aee600
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Jarek Kobus
2023-06-01 21:04:18 +02:00
parent 8da3575d72
commit 64d209c24b
3 changed files with 48 additions and 125 deletions

View File

@@ -59,25 +59,12 @@ static bool isSilverSearcherAvailable()
&& silverSearcherProcess.cleanedStdOut().contains("ag version");
}
static std::optional<QRegularExpression> regExpFromParameters(const FileFindParameters &parameters)
{
if (!(parameters.flags & FindRegularExpression))
return {};
const QRegularExpression::PatternOptions patternOptions
= (parameters.flags & FindCaseSensitively)
? QRegularExpression::NoPatternOption
: QRegularExpression::CaseInsensitiveOption;
QRegularExpression regExp;
regExp.setPattern(parameters.text);
regExp.setPatternOptions(patternOptions);
return regExp;
}
static void runSilverSeacher(QPromise<SearchResultItems> &promise,
const FileFindParameters &parameters)
{
const FilePath directory = FilePath::fromUserInput(parameters.additionalParameters.toString());
const auto setupProcess = [parameters](Process &process) {
const FilePath directory
= FilePath::fromUserInput(parameters.additionalParameters.toString());
QStringList arguments = {"--parallel", "--ackmate"};
if (parameters.flags & FindCaseSensitively)
@@ -107,66 +94,16 @@ static void runSilverSeacher(QPromise<SearchResultItems> &promise,
arguments << params.searchOptions.split(' ');
arguments << "--" << parameters.text << directory.normalizedPathName().toString();
QEventLoop loop;
Process process;
process.setCommand({"ag", arguments});
ParserState parserState;
const std::optional<QRegularExpression> regExp = regExpFromParameters(parameters);
QStringList outputBuffer;
// The states transition exactly in this order:
enum State { BelowLimit, AboveLimit, Paused, Resumed };
State state = BelowLimit;
process.setStdOutCallback([&process, &loop, &promise, &state, &outputBuffer, &parserState,
regExp](const QString &output) {
if (promise.isCanceled()) {
process.close();
loop.quit();
return;
}
// The SearchResultWidget is going to pause the search anyway, so start buffering
// the output.
if (state == AboveLimit || state == Paused) {
outputBuffer.append(output);
} else {
SilverSearcher::parse(promise, output, &parserState, regExp);
if (state == BelowLimit && parserState.m_reportedResultsCount > 200000)
state = AboveLimit;
}
});
QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] {
if (state == BelowLimit || state == Resumed || promise.isCanceled())
loop.quit();
});
};
process.start();
if (process.state() == QProcess::NotRunning)
return;
FilePath lastFilePath;
const auto outputParser = [&lastFilePath](const QFuture<void> &future, const QString &input,
const std::optional<QRegularExpression> &regExp) {
return SilverSearcher::parse(future, input, regExp, &lastFilePath);
};
QFutureWatcher<void> watcher;
QFuture<void> future(promise.future());
QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, [&process, &loop] {
process.close();
loop.quit();
});
QObject::connect(&watcher, &QFutureWatcherBase::paused, &loop, [&state] { state = Paused; });
QObject::connect(&watcher, &QFutureWatcherBase::resumed, &loop,
[&process, &loop, &promise, &state, &outputBuffer, &parserState, regExp] {
state = Resumed;
for (const QString &output : outputBuffer) {
if (promise.isCanceled()) {
process.close();
loop.quit();
}
SilverSearcher::parse(promise, output, &parserState, regExp);
}
outputBuffer.clear();
if (process.state() == QProcess::NotRunning)
loop.quit();
});
watcher.setFuture(future);
loop.exec(QEventLoop::ExcludeUserInputEvents);
TextEditor::searchInProcessOutput(promise, parameters, setupProcess, outputParser);
}
} // namespace

View File

@@ -3,8 +3,6 @@
#include "silversearcherparser.h"
#include <QFuture>
using namespace Utils;
namespace SilverSearcher {
@@ -96,28 +94,28 @@ static bool parseLineHits(QStringView *remainingInput, QList<QPair<int, int>> *h
return true;
}
void parse(QPromise<SearchResultItems> &promise, const QString &input,
ParserState *parserState, const std::optional<QRegularExpression> &regExp)
SearchResultItems parse(const QFuture<void> &future, const QString &input,
const std::optional<QRegularExpression> &regExp, FilePath *lastFilePath)
{
QTC_ASSERT(parserState, return);
QTC_ASSERT(lastFilePath, return {});
SearchResultItems items;
QStringView remainingInput(input);
while (true) {
if (promise.isCanceled())
return;
if (future.isCanceled())
return {};
if (remainingInput.isEmpty())
break;
const QStringView filePathLine = nextLine(&remainingInput);
if (filePathLine.isEmpty()) {
parserState->m_lastFilePath = {}; // Clear the parser state
*lastFilePath = {}; // Clear the parser state
continue;
}
if (filePathLine.startsWith(':'))
parserState->m_lastFilePath = FilePath::fromPathPart(filePathLine.mid(1));
*lastFilePath = FilePath::fromPathPart(filePathLine.mid(1));
while (true) {
QStringView hitLine = nextLine(&remainingInput);
@@ -133,7 +131,7 @@ void parse(QPromise<SearchResultItems> &promise, const QString &input,
break;
SearchResultItem item;
item.setFilePath(parserState->m_lastFilePath);
item.setFilePath(*lastFilePath);
item.setDisplayText(hitLine.toString());
item.setUseTextEditorFont(true);
for (const QPair<int, int> &hit : hits) {
@@ -145,20 +143,15 @@ void parse(QPromise<SearchResultItems> &promise, const QString &input,
}
}
}
if (!items.isEmpty())
promise.addResult(items);
parserState->m_reportedResultsCount += items.count();
return items;
}
SearchResultItems parse(const QString &input, const std::optional<QRegularExpression> &regExp)
{
QPromise<SearchResultItems> promise;
QPromise<void> promise;
promise.start();
ParserState dummy;
SilverSearcher::parse(promise, input, &dummy, regExp);
promise.finish();
return promise.future().resultCount() ? promise.future().result() : SearchResultItems();
FilePath dummy;
return SilverSearcher::parse(promise.future(), input, regExp, &dummy);
}
} // namespace SilverSearcher

View File

@@ -5,23 +5,16 @@
#include <utils/searchresultitem.h>
#include <QPromise>
#include <QFuture>
#include <QRegularExpression>
namespace Utils { class FilePath; }
namespace SilverSearcher {
class ParserState
{
public:
Utils::FilePath m_lastFilePath;
int m_reportedResultsCount = 0;
};
void parse(QPromise<Utils::SearchResultItems> &promise, const QString &input,
ParserState *parserState = nullptr,
const std::optional<QRegularExpression> &regExp = {});
Utils::SearchResultItems parse(const QFuture<void> &future, const QString &input,
const std::optional<QRegularExpression> &regExp,
Utils::FilePath *lastFilePath);
Utils::SearchResultItems parse(const QString &input,
const std::optional<QRegularExpression> &regExp = {});