GitGrep: Make pause and continue working

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

Applied the same pattern as it was done recently inside
SilverSearcher: cd70d10dce.

Change-Id: I5e466e2176a59301dbfd3f957012e1760bd0c20f
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 18:59:53 +02:00
parent 7a42c32732
commit 7b2c1fdab0

View File

@@ -126,13 +126,13 @@ public:
}
}
void read(QPromise<SearchResultItems> &promise, const QString &input)
int read(QPromise<SearchResultItems> &promise, const QString &input)
{
SearchResultItems items;
QStringView remainingInput(input);
while (true) {
if (promise.isCanceled())
return;
return 0;
if (remainingInput.isEmpty())
break;
@@ -145,6 +145,7 @@ public:
}
if (!items.isEmpty())
promise.addResult(items);
return items.count();
}
void operator()(QPromise<SearchResultItems> &promise)
@@ -181,26 +182,66 @@ public:
});
arguments << "--" << filterArgs << exclusionArgs;
QEventLoop loop;
Process process;
process.setEnvironment(m_environment);
process.setCommand({m_vcsBinary, arguments});
process.setWorkingDirectory(m_directory);
process.setStdOutCallback([this, &promise](const QString &text) { read(promise, text); });
process.start();
process.waitForFinished();
QStringList outputBuffer;
// The states transition exactly in this order:
enum State { BelowLimit, AboveLimit, Paused, Resumed };
State state = BelowLimit;
int reportedResultsCount = 0;
process.setStdOutCallback([this, &process, &loop, &promise, &state, &reportedResultsCount,
&outputBuffer](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 {
reportedResultsCount += read(promise, output);
if (state == BelowLimit && reportedResultsCount > 200000)
state = AboveLimit;
}
});
QObject::connect(&process, &Process::done, &loop, [&loop, &promise, &state] {
if (state == BelowLimit || state == Resumed || promise.isCanceled())
loop.quit();
});
switch (process.result()) {
case ProcessResult::TerminatedAbnormally:
case ProcessResult::StartFailed:
case ProcessResult::Hang:
promise.future().cancel();
break;
case ProcessResult::FinishedWithSuccess:
case ProcessResult::FinishedWithError:
// When no results are found, git-grep exits with non-zero status.
// Do not consider this as an error.
break;
}
process.start();
if (process.state() == QProcess::NotRunning)
return;
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,
[this, &process, &loop, &promise, &state, &outputBuffer] {
state = Resumed;
for (const QString &output : outputBuffer) {
if (promise.isCanceled()) {
process.close();
loop.quit();
}
read(promise, output);
}
outputBuffer.clear();
if (process.state() == QProcess::NotRunning)
loop.quit();
});
watcher.setFuture(future);
loop.exec(QEventLoop::ExcludeUserInputEvents);
}
private: