SilverSearcher: Don't crash on giant output from ag

Make cancel and continue button working. Make pausing
above 200000 hits working.

Fixes: QTCREATORBUG-29130
Change-Id: I55429ae1b4d80dacfcd7e8366133657d0c44a0d6
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 13:02:25 +02:00
parent 333cea6ef5
commit cd70d10dce

View File

@@ -114,10 +114,31 @@ static void runSilverSeacher(QPromise<SearchResultItems> &promise,
process.setCommand({"ag", arguments});
ParserState parserState;
const std::optional<QRegularExpression> regExp = regExpFromParameters(parameters);
process.setStdOutCallback([&promise, &parserState, regExp](const QString &output) {
SilverSearcher::parse(promise, output, &parserState, regExp);
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();
});
QObject::connect(&process, &Process::done, &loop, &QEventLoop::quit);
process.start();
if (process.state() == QProcess::NotRunning)
@@ -125,7 +146,23 @@ static void runSilverSeacher(QPromise<SearchResultItems> &promise,
QFutureWatcher<void> watcher;
QFuture<void> future(promise.future());
QObject::connect(&watcher, &QFutureWatcherBase::canceled, &loop, &QEventLoop::quit);
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();
});
watcher.setFuture(future);
loop.exec(QEventLoop::ExcludeUserInputEvents);
}