Add new search predicate to enable searching for messages matching a regex (#3282)

Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
LosFarmosCTL
2021-10-17 14:36:44 +02:00
committed by GitHub
parent c1a3814b7c
commit 06245f3713
6 changed files with 109 additions and 39 deletions
+41 -39
View File
@@ -11,6 +11,7 @@
#include "messages/search/ChannelPredicate.hpp"
#include "messages/search/LinkPredicate.hpp"
#include "messages/search/MessageFlagsPredicate.hpp"
#include "messages/search/RegexPredicate.hpp"
#include "messages/search/SubstringPredicate.hpp"
#include "util/Shortcut.hpp"
#include "widgets/helper/ChannelView.hpp"
@@ -164,51 +165,56 @@ void SearchPopup::initLayout()
std::vector<std::unique_ptr<MessagePredicate>> SearchPopup::parsePredicates(
const QString &input)
{
static QRegularExpression predicateRegex(R"(^(\w+):([\w,]+)$)");
// This regex captures all name:value predicate pairs into named capturing
// groups and matches all other inputs seperated by spaces as normal
// strings.
// It also ignores whitespaces in values when being surrounded by quotation
// marks, to enable inputs like this => regex:"kappa 123"
static QRegularExpression predicateRegex(
R"lit((?:(?<name>\w+):(?<value>".+?"|[^\s]+))|[^\s]+?(?=$|\s))lit");
static QRegularExpression trimQuotationMarksRegex(R"(^"|"$)");
QRegularExpressionMatchIterator it = predicateRegex.globalMatch(input);
std::vector<std::unique_ptr<MessagePredicate>> predicates;
auto words = input.split(' ', QString::SkipEmptyParts);
QStringList authors;
QStringList channels;
for (auto it = words.begin(); it != words.end();)
while (it.hasNext())
{
if (auto match = predicateRegex.match(*it); match.hasMatch())
QRegularExpressionMatch match = it.next();
QString name = match.captured("name");
QString value = match.captured("value");
value.remove(trimQuotationMarksRegex);
// match predicates
if (name == "from")
{
QString name = match.captured(1);
QString value = match.captured(2);
bool remove = true;
// match predicates
if (name == "from")
{
authors.append(value);
}
else if (name == "has" && value == "link")
{
predicates.push_back(std::make_unique<LinkPredicate>());
}
else if (name == "in")
{
channels.append(value);
}
else if (name == "is")
{
predicates.push_back(
std::make_unique<MessageFlagsPredicate>(value));
}
else
{
remove = false;
}
// remove or advance
it = remove ? words.erase(it) : ++it;
authors.append(value);
}
else if (name == "has" && value == "link")
{
predicates.push_back(std::make_unique<LinkPredicate>());
}
else if (name == "in")
{
channels.append(value);
}
else if (name == "is")
{
predicates.push_back(
std::make_unique<MessageFlagsPredicate>(value));
}
else if (name == "regex")
{
predicates.push_back(std::make_unique<RegexPredicate>(value));
}
else
{
++it;
predicates.push_back(
std::make_unique<SubstringPredicate>(match.captured()));
}
}
@@ -218,10 +224,6 @@ std::vector<std::unique_ptr<MessagePredicate>> SearchPopup::parsePredicates(
if (!channels.empty())
predicates.push_back(std::make_unique<ChannelPredicate>(channels));
if (!words.empty())
predicates.push_back(
std::make_unique<SubstringPredicate>(words.join(" ")));
return predicates;
}