Skip to content

Commit

Permalink
API: Add variadic Matcher::match(…)
Browse files Browse the repository at this point in the history
  • Loading branch information
ManuelSchneid3r committed Nov 11, 2024
1 parent 0e1ac0b commit 2d364e2
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 34 deletions.
16 changes: 15 additions & 1 deletion include/albert/matchconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,37 @@ namespace albert
///
/// Configuration for string matching.
///
/// \sa \ref Matcher, \ref IndexQueryHandler
///
class ALBERT_EXPORT MatchConfig
{
public:
///
/// The separator regex used to split the compared strings.
///
QRegularExpression separator_regex =
QRegularExpression(R"([\s\\\/\-\[\](){}#!?<>"'=+*.:,;_]+)");
// QRegularExpression(R"([\s\\\/\-\[\](){}#!?<>"'=+*.:,;_]+)");
// make doxygen happy
QRegularExpression("([\\s\\\\/\\-\\[\\](){}#!?<>\"'=+*.:,;_]+)");

///
/// Match strings case insensitive.
///
bool ignore_case = true;

///
/// Match strings normalized.
///
bool ignore_diacritics = true;

///
/// Match strings independent of their order.
///
bool ignore_word_order = true;

///
/// Match strings error tolerant.
///
bool fuzzy = false;

///
Expand Down
101 changes: 83 additions & 18 deletions include/albert/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,64 +10,129 @@ class MatcherPrivate;

namespace albert
{
class Item;

///
/// The Match class.
///
/// Utility class encapsulating and augmenting the match score.
/// Augmented match score.
///
/// Some nifty features:
/// - The bool type conversion evaluates to isMatch()
/// - The Score/double type conversion seamlessly uses the score
/// - The bool type conversion evaluates to \ref isMatch()
/// - The Score/double type conversion seamlessly uses the \ref score()
///
/// @sa \ref Matcher
///
class ALBERT_EXPORT Match final
{
public:
using Score = double;

///
/// Constructs an invalid match.
///
Match() : score_(-1.) {}

///
/// Constructs a match with the given `score`.
///
Match(const Score score) : score_(score) {}

///
/// Constructs a #Match with the score of `other`.
///
Match(const Match &o) = default;
Match(Match &&o) = default;

///
/// Replaces the score with that of `other`.
///
Match &operator=(const Match &o) = default;
Match &operator=(Match &&o) = default;

inline operator bool() const { return isMatch(); }
inline explicit operator Score() const { return score_; }
///
/// Returns `true` if this is a match, otherwise returns `false`.
///
inline bool isMatch() const { return score_ >= 0.0; }

///
/// Returns `true` if this is a zero score match, otherwise returns `false`.
///
inline bool isEmptyMatch() const { return qFuzzyCompare(score_, 0.0); }

///
/// Returns `true` if this is a perfect match, otherwise returns `false`.
///
inline bool isExactMatch() const { return qFuzzyCompare(score_, 1.0); }

///
/// Returns the score.
///
inline Score score() const { return score_; }

///
/// Returns `true` if this is a match, otherwise returns `false`.
///
inline operator bool() const { return isMatch(); }

///
/// Returns the score.
///
inline explicit operator Score() const { return score_; }

private:

Score score_;
};


///
/// The Matcher class.
/// Configurable string matcher.
///
/// Use this class to get unified user experience in match behavior.
///
/// @note Experimental WIP
/// @sa \ref MatchConfig, \ref Match
///
class ALBERT_EXPORT Matcher final
{
public:
///
/// Constructs a Matcher with the given `string` and match `config`.
///
/// If `config` is not provided, a default constructed config is used.
///
Matcher(const QString &string, MatchConfig config = {});

Matcher(const QString &query, MatchConfig config = {});
///
/// Constructs a Matcher with the contents of `other` using move semantics.
///
Matcher(Matcher &&o);

///
/// Replaces the contents with those of `other` using move semantics.
///
Matcher &operator=(Matcher &&o);

///
/// Destructs the Matcher.
///
~Matcher();

Match match(const Item &item) const;
///
/// Returns the string matched against.
///
const QString &string() const;

///
/// Returns a Match for `string`.
///
Match match(const QString &string) const;

private:
///
/// Returns a Match for the given strings.
///
template<typename T, typename... Args>
Match match(T first, Args... args) const {
return std::max(match(first), match(args...));
}

std::unique_ptr<MatcherPrivate> d;

private:
class Private;
std::unique_ptr<Private> d;

};

Expand Down
11 changes: 1 addition & 10 deletions src/app/triggersqueryhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,9 @@ void TriggersQueryHandler::handleTriggerQuery(Query *q)
// Match tigger, id and name.

vector<RankItem> RI;
Matcher matcher(q->string());

for (const auto &[trigger, handler] : query_engine_.activeTriggerHandlers())
{
Match m;
for (const auto &s : {trigger, handler->name(), handler->id()})
if (auto _m = matcher.match(s); m < _m)
m = _m;

if (m.isMatch())
if (auto m = Matcher(q->string()).match(trigger, handler->name(), handler->id()); m)
RI.emplace_back(make_item(trigger, handler), m);
}

applyUsageScore(&RI);

Expand Down
7 changes: 2 additions & 5 deletions src/util/matcher.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// SPDX-FileCopyrightText: 2024 Manuel Schneider

#include "item.h"
#include "levenshtein.h"
#include "matchconfig.h"
#include "matcher.h"
Expand All @@ -9,7 +8,7 @@
using namespace albert;
using namespace std;

class MatcherPrivate
class Matcher::Private
{
public:

Expand Down Expand Up @@ -102,7 +101,7 @@ class MatcherPrivate
};

Matcher::Matcher(const QString &query, MatchConfig config):
d(new MatcherPrivate{
d(new Private{
.config = ::move(config),
.string = query,
.levenshtein = {},
Expand All @@ -116,6 +115,4 @@ Matcher::~Matcher() = default;

Matcher &Matcher::operator=(Matcher &&o) = default;

Match Matcher::match(const Item &item) const { return d->match(item.text()); }

Match Matcher::match(const QString &s) const { return d->match(s); }

0 comments on commit 2d364e2

Please sign in to comment.