forked from qt-creator/qt-creator
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:
@@ -59,25 +59,12 @@ static bool isSilverSearcherAvailable()
|
|||||||
&& silverSearcherProcess.cleanedStdOut().contains("ag version");
|
&& silverSearcherProcess.cleanedStdOut().contains("ag version");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<QRegularExpression> regExpFromParameters(const FileFindParameters ¶meters)
|
|
||||||
{
|
|
||||||
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,
|
static void runSilverSeacher(QPromise<SearchResultItems> &promise,
|
||||||
const FileFindParameters ¶meters)
|
const FileFindParameters ¶meters)
|
||||||
{
|
{
|
||||||
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"};
|
QStringList arguments = {"--parallel", "--ackmate"};
|
||||||
|
|
||||||
if (parameters.flags & FindCaseSensitively)
|
if (parameters.flags & FindCaseSensitively)
|
||||||
@@ -107,66 +94,16 @@ static void runSilverSeacher(QPromise<SearchResultItems> &promise,
|
|||||||
arguments << params.searchOptions.split(' ');
|
arguments << params.searchOptions.split(' ');
|
||||||
|
|
||||||
arguments << "--" << parameters.text << directory.normalizedPathName().toString();
|
arguments << "--" << parameters.text << directory.normalizedPathName().toString();
|
||||||
|
|
||||||
QEventLoop loop;
|
|
||||||
|
|
||||||
Process process;
|
|
||||||
process.setCommand({"ag", arguments});
|
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();
|
FilePath lastFilePath;
|
||||||
if (process.state() == QProcess::NotRunning)
|
const auto outputParser = [&lastFilePath](const QFuture<void> &future, const QString &input,
|
||||||
return;
|
const std::optional<QRegularExpression> ®Exp) {
|
||||||
|
return SilverSearcher::parse(future, input, regExp, &lastFilePath);
|
||||||
|
};
|
||||||
|
|
||||||
QFutureWatcher<void> watcher;
|
TextEditor::searchInProcessOutput(promise, parameters, setupProcess, outputParser);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include "silversearcherparser.h"
|
#include "silversearcherparser.h"
|
||||||
|
|
||||||
#include <QFuture>
|
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace SilverSearcher {
|
namespace SilverSearcher {
|
||||||
@@ -96,28 +94,28 @@ static bool parseLineHits(QStringView *remainingInput, QList<QPair<int, int>> *h
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse(QPromise<SearchResultItems> &promise, const QString &input,
|
SearchResultItems parse(const QFuture<void> &future, const QString &input,
|
||||||
ParserState *parserState, const std::optional<QRegularExpression> ®Exp)
|
const std::optional<QRegularExpression> ®Exp, FilePath *lastFilePath)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(parserState, return);
|
QTC_ASSERT(lastFilePath, return {});
|
||||||
SearchResultItems items;
|
SearchResultItems items;
|
||||||
|
|
||||||
QStringView remainingInput(input);
|
QStringView remainingInput(input);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (promise.isCanceled())
|
if (future.isCanceled())
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
if (remainingInput.isEmpty())
|
if (remainingInput.isEmpty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const QStringView filePathLine = nextLine(&remainingInput);
|
const QStringView filePathLine = nextLine(&remainingInput);
|
||||||
if (filePathLine.isEmpty()) {
|
if (filePathLine.isEmpty()) {
|
||||||
parserState->m_lastFilePath = {}; // Clear the parser state
|
*lastFilePath = {}; // Clear the parser state
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filePathLine.startsWith(':'))
|
if (filePathLine.startsWith(':'))
|
||||||
parserState->m_lastFilePath = FilePath::fromPathPart(filePathLine.mid(1));
|
*lastFilePath = FilePath::fromPathPart(filePathLine.mid(1));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
QStringView hitLine = nextLine(&remainingInput);
|
QStringView hitLine = nextLine(&remainingInput);
|
||||||
@@ -133,7 +131,7 @@ void parse(QPromise<SearchResultItems> &promise, const QString &input,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
SearchResultItem item;
|
SearchResultItem item;
|
||||||
item.setFilePath(parserState->m_lastFilePath);
|
item.setFilePath(*lastFilePath);
|
||||||
item.setDisplayText(hitLine.toString());
|
item.setDisplayText(hitLine.toString());
|
||||||
item.setUseTextEditorFont(true);
|
item.setUseTextEditorFont(true);
|
||||||
for (const QPair<int, int> &hit : hits) {
|
for (const QPair<int, int> &hit : hits) {
|
||||||
@@ -145,20 +143,15 @@ void parse(QPromise<SearchResultItems> &promise, const QString &input,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!items.isEmpty())
|
return items;
|
||||||
promise.addResult(items);
|
|
||||||
|
|
||||||
parserState->m_reportedResultsCount += items.count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResultItems parse(const QString &input, const std::optional<QRegularExpression> ®Exp)
|
SearchResultItems parse(const QString &input, const std::optional<QRegularExpression> ®Exp)
|
||||||
{
|
{
|
||||||
QPromise<SearchResultItems> promise;
|
QPromise<void> promise;
|
||||||
promise.start();
|
promise.start();
|
||||||
ParserState dummy;
|
FilePath dummy;
|
||||||
SilverSearcher::parse(promise, input, &dummy, regExp);
|
return SilverSearcher::parse(promise.future(), input, regExp, &dummy);
|
||||||
promise.finish();
|
|
||||||
return promise.future().resultCount() ? promise.future().result() : SearchResultItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace SilverSearcher
|
} // namespace SilverSearcher
|
||||||
|
|||||||
@@ -5,23 +5,16 @@
|
|||||||
|
|
||||||
#include <utils/searchresultitem.h>
|
#include <utils/searchresultitem.h>
|
||||||
|
|
||||||
#include <QPromise>
|
#include <QFuture>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace Utils { class FilePath; }
|
namespace Utils { class FilePath; }
|
||||||
|
|
||||||
namespace SilverSearcher {
|
namespace SilverSearcher {
|
||||||
|
|
||||||
class ParserState
|
Utils::SearchResultItems parse(const QFuture<void> &future, const QString &input,
|
||||||
{
|
const std::optional<QRegularExpression> ®Exp,
|
||||||
public:
|
Utils::FilePath *lastFilePath);
|
||||||
Utils::FilePath m_lastFilePath;
|
|
||||||
int m_reportedResultsCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
void parse(QPromise<Utils::SearchResultItems> &promise, const QString &input,
|
|
||||||
ParserState *parserState = nullptr,
|
|
||||||
const std::optional<QRegularExpression> ®Exp = {});
|
|
||||||
|
|
||||||
Utils::SearchResultItems parse(const QString &input,
|
Utils::SearchResultItems parse(const QString &input,
|
||||||
const std::optional<QRegularExpression> ®Exp = {});
|
const std::optional<QRegularExpression> ®Exp = {});
|
||||||
|
|||||||
Reference in New Issue
Block a user