Improvements to Message Search (#1237)

* Ran clang-format

* Implement user-specific search in message history

This functionality was originally requested in #1236.

This commit changes the SearchPopup::performSearch method so that only
messages from specific users can be shown.

In order to filter for a specific user, enter their username with a
leading '@' in the search popup. You can also add an additional search
phrase which will also be considered in the search.

* Naive implementation for "from:" tags

Rebase later?

* Cleverer (?) version using Predicates

Commit adds two POC predicates: one for the author of messages, and one
for substring search in messages.

Problems/TODOs:
* Best way to register new predicates?
* Clean up tags (e.g. "from:") or not?
* Test combinations of different predicates

* Add a predicate to check for links in messages

* Remove a dumb TODO

* Rewrite SearchPopup::performSearch to be cleaner

* Ran clang-format on all files

* Remove TODO I missed earlier

* Forgot to run clang-format

peepoSadDank

* Re-use {}-initialization

Was accidentally removed when fixing earlier merge conflict.

* Does this fix line endings?

No diffs are shown locally, hopefully Git doesn't lie to me.

* Rename "predicates" directory to "search"

Resolving one conversation in the review of #1237.

* Use LinkParser in LinkPredicate

Resolving a conversation in the review of #1237.

* Predicates: Use unique_ptr instead of shared_ptr

Resolves a conversation in the review of #1237.

* Refactor of SearchPopup and AuthorPredicate

Resolving some points from the review in #1237.

* Moved parsing of comma-seperated values into AuthorPredicate
  constructor.
* Rewrite SearchPopup::parsePredicates as suggested.
* Deleted now redundant methods in SearchPopup.

* MessagePredicate::appliesTo now takes a Message&

... instead of a MessagePtr.

This resolves a conversation in the review of #1237.

* Run clang-format on two files I missed

* AuthorPredicate: Check for displayName & loginName

Resolving conversation on #1237.
This commit is contained in:
Leon Richardt
2019-09-09 15:21:49 +02:00
committed by fourtf
parent 6cd3cfe79f
commit 720e5aa25f
15 changed files with 323 additions and 26 deletions
+24
View File
@@ -0,0 +1,24 @@
#include "messages/search/AuthorPredicate.hpp"
namespace chatterino {
AuthorPredicate::AuthorPredicate(const QStringList &authors)
: authors_()
{
// Check if any comma-seperated values were passed and transform those
for (const auto &entry : authors)
{
for (const auto &author : entry.split(',', QString::SkipEmptyParts))
{
this->authors_ << author;
}
}
}
bool AuthorPredicate::appliesTo(const Message &message)
{
return authors_.contains(message.displayName, Qt::CaseInsensitive) ||
authors_.contains(message.loginName, Qt::CaseInsensitive);
}
} // namespace chatterino
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include "messages/search/MessagePredicate.hpp"
namespace chatterino {
/**
* @brief MessagePredicate checking for the author/sender of a message.
*
* This predicate will only allow messages that are sent by a list of users,
* specified by their user names.
*/
class AuthorPredicate : public MessagePredicate
{
public:
/**
* @brief Create an AuthorPredicate with a list of users to search for.
*
* @param authors a list of user names that a message should be sent from
*/
AuthorPredicate(const QStringList &authors);
/**
* @brief Checks whether the message is authored by any of the users passed
* in the constructor.
*
* @param message the message to check
* @return true if the message was authored by one of the specified users,
* false otherwise
*/
bool appliesTo(const Message &message);
private:
/// Holds the user names that will be searched for
QStringList authors_;
};
} // namespace chatterino
+22
View File
@@ -0,0 +1,22 @@
#include "messages/search/LinkPredicate.hpp"
#include "common/LinkParser.hpp"
namespace chatterino {
LinkPredicate::LinkPredicate()
{
}
bool LinkPredicate::appliesTo(const Message &message)
{
for (const auto &word :
message.messageText.split(' ', QString::SkipEmptyParts))
{
if (LinkParser(word).hasMatch())
return true;
}
return false;
}
} // namespace chatterino
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "messages/search/MessagePredicate.hpp"
namespace chatterino {
/**
* @brief MessagePredicate checking whether a link exists in the message.
*
* This predicate will only allow messages that contain a link.
*/
class LinkPredicate : public MessagePredicate
{
public:
LinkPredicate();
/**
* @brief Checks whether the message contains a link.
*
* @param message the message to check
* @return true if the message contains a link, false otherwise
*/
bool appliesTo(const Message &message);
};
} // namespace chatterino
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include "messages/Message.hpp"
#include <memory>
namespace chatterino {
/**
* @brief Abstract base class for message predicates.
*
* Message predicates define certain features a message can satisfy.
* Features are represented by classes derived from this abstract class.
* A derived class must override `appliesTo` in order to test for the desired
* feature.
*/
class MessagePredicate
{
public:
/**
* @brief Checks whether this predicate applies to the passed message.
*
* Implementations of `appliesTo` should never change the message's content
* in order to be compatible with other MessagePredicates.
*
* @param message the message to check for this predicate
* @return true if this predicate applies, false otherwise
*/
virtual bool appliesTo(const Message &message) = 0;
};
} // namespace chatterino
@@ -0,0 +1,15 @@
#include "messages/search/SubstringPredicate.hpp"
namespace chatterino {
SubstringPredicate::SubstringPredicate(const QString &search)
: search_(search)
{
}
bool SubstringPredicate::appliesTo(const Message &message)
{
return message.messageText.contains(this->search_, Qt::CaseInsensitive);
}
} // namespace chatterino
@@ -0,0 +1,41 @@
#pragma once
#include "messages/search/MessagePredicate.hpp"
namespace chatterino {
/**
* @brief MessagePredicate checking whether a substring exists in the message.
*
* This predicate will only allow messages that contain a certain substring in
* their `searchText`.
*/
class SubstringPredicate : public MessagePredicate
{
public:
/**
* @brief Create a SubstringPredicate with a substring to search for.
*
* The passed string is searched for case-insensitively.
*
* @param search the string to search for in the message
*/
SubstringPredicate(const QString &search);
/**
* @brief Checks whether the message contains the substring passed in the
* constructor.
*
* The check is done case-insensitively.
*
* @param message the message to check
* @return true if the message contains the substring, false otherwise
*/
bool appliesTo(const Message &message);
private:
/// Holds the substring to search for in a message's `messageText`
const QString search_;
};
} // namespace chatterino