message: fields: rationalize flags

Improve naming.
This commit is contained in:
Dirk-Jan C. Binnema 2022-03-19 18:41:05 +02:00
parent d4285975b3
commit 7f15767faf
4 changed files with 137 additions and 77 deletions

View File

@ -18,6 +18,7 @@
*/ */
#include "mu-message-fields.hh" #include "mu-message-fields.hh"
#include "mu-message-flags.hh"
using namespace Mu; using namespace Mu;
@ -66,6 +67,35 @@ validate_message_field_shortcuts()
} }
return true; return true;
} }
constexpr /*static*/ bool
validate_message_field_flags()
{
for (auto&& field: MessageFields) {
/* - A field has at most one of Indexable, HasTerms, IsXapianBoolean and
IsContact. */
size_t flagnum{};
if (field.is_indexable_term())
++flagnum;
if (field.is_boolean_term())
++flagnum;
if (field.is_normal_term())
++flagnum;
if (field.is_contact())
++flagnum;
if (flagnum > 1) {
//g_warning("invalid field %*s", STR_V(field.name));
return false;
}
}
return true;
}
/* /*
* tests... also build as runtime-tests, so we can get coverage info * tests... also build as runtime-tests, so we can get coverage info
*/ */
@ -96,6 +126,13 @@ test_prefix()
static_assert(message_field(MessageField::Id::BodyHtml).xapian_prefix() == 0); static_assert(message_field(MessageField::Id::BodyHtml).xapian_prefix() == 0);
} }
[[maybe_unused]]
static void
test_field_flags()
{
static_assert(validate_message_field_flags());
}
#ifdef BUILD_TESTS #ifdef BUILD_TESTS
static void static void
@ -120,6 +157,7 @@ main(int argc, char* argv[])
g_test_add_func("/message/fields/shortcuts", test_shortcuts); g_test_add_func("/message/fields/shortcuts", test_shortcuts);
g_test_add_func("/message/fields/prefix", test_prefix); g_test_add_func("/message/fields/prefix", test_prefix);
g_test_add_func("/message/fields/xapian-term", test_xapian_term); g_test_add_func("/message/fields/xapian-term", test_xapian_term);
g_test_add_func("/message/fields/flags", test_field_flags);
return g_test_run(); return g_test_run();
} }

View File

@ -55,7 +55,6 @@ struct MessageField {
Path, /**< File-system Path */ Path, /**< File-system Path */
Subject, /**< Message subject */ Subject, /**< Message subject */
To, /**< To: recipient */ To, /**< To: recipient */
Uid, /**< Unique id for message (based on path) */
/* /*
* string list items... * string list items...
*/ */
@ -89,7 +88,6 @@ struct MessageField {
return static_cast<size_t>(Id::_count_); return static_cast<size_t>(Id::_count_);
} }
constexpr Xapian::valueno value_no() const { constexpr Xapian::valueno value_no() const {
return static_cast<Xapian::valueno>(id); return static_cast<Xapian::valueno>(id);
} }
@ -121,39 +119,58 @@ struct MessageField {
* can be multiple terms, each containing e.g. one of the To: * can be multiple terms, each containing e.g. one of the To:
* addresses - searching uses terms, but to display some field, it * addresses - searching uses terms, but to display some field, it
* must be in the value (at least when using MuMsgIter) * must be in the value (at least when using MuMsgIter)
*
* Rules (build-time enforced):
* - A field has at most one of Indexable, HasTerms, IsXapianBoolean and IsContact.
*/ */
enum struct Flag { enum struct Flag {
GMime = 1 << 0, GMime = 1 << 0,
/**< Field retrieved through gmime */ /**< Field retrieved through gmime */
FullText = 1 << 1,
/**< Field-text is indexed in xapian (i.e., the text is processed */ /*
Searchable = 1 << 2, * Different kind of terms; at most one is true,
* and cannot be combined with IsContact. Compile-time enforced.
*/
NormalTerm = 1 << 2,
/**< Field is a searchable term */ /**< Field is a searchable term */
Value = 1 << 3, BooleanTerm = 1 << 5,
/**< Field is a boolean search-term; wildcards do not work */
IndexableTerm = 1 << 1,
/**< Field has indexable text as term */
/*
* Contact flag cannot be combined with any of the term flags.
* This is compile-time enforced.
*/
Contact = 1 << 4,
/**< field contains one or more e-mail-addresses */
Value = 1 << 3,
/**< Field value is stored (so the literal value can be retrieved) */ /**< Field value is stored (so the literal value can be retrieved) */
Contact = 1 << 4,
/**< field contains one or more * e-mail-addresses */ DoNotCache = 1 << 6,
XapianBoolean = 1 << 5,
/**< use 'add_boolean_prefix' for Xapian queries; wildcards do NOT WORK for such
* fields */
DoNotCache = 1 << 6,
/**< don't cache this field in * the MuMsg cache */ /**< don't cache this field in * the MuMsg cache */
Range = 1 << 7 /**< whether this is a range field (e.g., date, size)*/ Range = 1 << 7
/**< whether this is a range field (e.g., date, size)*/
}; };
constexpr bool any_of(Flag some_flag) const{ constexpr bool any_of(Flag some_flag) const{
return (static_cast<int>(some_flag) & static_cast<int>(flags)) != 0; return (static_cast<int>(some_flag) & static_cast<int>(flags)) != 0;
} }
constexpr bool is_gmime() const { return any_of(Flag::Value); } constexpr bool is_gmime() const { return any_of(Flag::GMime); }
constexpr bool is_full_text() const { return any_of(Flag::FullText); }
constexpr bool is_searchable() const { return any_of(Flag::Searchable); } constexpr bool is_indexable_term() const { return any_of(Flag::IndexableTerm); }
constexpr bool is_value() const { return any_of(Flag::Value); } constexpr bool is_boolean_term() const { return any_of(Flag::BooleanTerm); }
constexpr bool is_contact() const { return any_of(Flag::Contact); } constexpr bool is_normal_term() const { return any_of(Flag::NormalTerm); }
constexpr bool is_xapian_boolean() const { return any_of(Flag::XapianBoolean); }
constexpr bool is_range() const { return any_of(Flag::Range); } constexpr bool is_value() const { return any_of(Flag::Value); }
constexpr bool do_not_cache() const { return any_of(Flag::DoNotCache); }
constexpr bool is_contact() const { return any_of(Flag::Contact); }
constexpr bool is_range() const { return any_of(Flag::Range); }
constexpr bool do_not_cache() const { return any_of(Flag::DoNotCache); }
/** /**
* Field members * Field members
@ -190,7 +207,6 @@ MU_ENABLE_BITOPS(MessageField::Flag);
static constexpr std::array<MessageField, MessageField::id_size()> static constexpr std::array<MessageField, MessageField::id_size()>
MessageFields = { MessageFields = {
{ {
// Bcc // Bcc
{ {
MessageField::Id::Bcc, MessageField::Id::Bcc,
@ -199,8 +215,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Blind carbon-copy recipient", "Blind carbon-copy recipient",
"bcc:foo@example.com", "bcc:foo@example.com",
'h', 'h',
MessageField::Flag::GMime | MessageField::Flag::Contact | MessageField::Flag::GMime |
MessageField::Flag::Value}, MessageField::Flag::Contact |
MessageField::Flag::Value
},
// HTML Body // HTML Body
{ {
MessageField::Id::BodyHtml, MessageField::Id::BodyHtml,
@ -209,7 +227,9 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message html body", "Message html body",
{}, {},
{}, {},
MessageField::Flag::GMime | MessageField::Flag::DoNotCache}, MessageField::Flag::GMime |
MessageField::Flag::DoNotCache
},
// Body // Body
{ {
MessageField::Id::BodyText, MessageField::Id::BodyText,
@ -218,9 +238,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message plain-text body", "Message plain-text body",
"body:capybara", // example "body:capybara", // example
'b', 'b',
MessageField::Flag::GMime | MessageField::Flag::FullText | MessageField::Flag::GMime |
MessageField::Flag::DoNotCache}, MessageField::Flag::IndexableTerm |
MessageField::Flag::DoNotCache
},
// Cc // Cc
{ {
MessageField::Id::Cc, MessageField::Id::Cc,
@ -229,7 +250,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Carbon-copy recipient", "Carbon-copy recipient",
"cc:quinn@example.com", "cc:quinn@example.com",
'c', 'c',
MessageField::Flag::GMime | MessageField::Flag::Contact | MessageField::Flag::GMime |
MessageField::Flag::Contact |
MessageField::Flag::Value}, MessageField::Flag::Value},
// Embed // Embed
@ -240,7 +262,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Embedded text", "Embedded text",
"embed:war OR embed:peace", "embed:war OR embed:peace",
'e', 'e',
MessageField::Flag::GMime | MessageField::Flag::FullText | MessageField::Flag::GMime |
MessageField::Flag::IndexableTerm |
MessageField::Flag::DoNotCache}, MessageField::Flag::DoNotCache},
// File // File
{ {
@ -250,7 +273,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Attachment file name", "Attachment file name",
"file:/image\\.*.jpg/", "file:/image\\.*.jpg/",
'j', 'j',
MessageField::Flag::GMime | MessageField::Flag::Searchable | MessageField::Flag::GMime |
MessageField::Flag::NormalTerm |
MessageField::Flag::DoNotCache}, MessageField::Flag::DoNotCache},
// From // From
@ -261,7 +285,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message sender", "Message sender",
"from:jimbo", "from:jimbo",
'f', 'f',
MessageField::Flag::GMime | MessageField::Flag::Contact | MessageField::Flag::GMime |
MessageField::Flag::Contact |
MessageField::Flag::Value}, MessageField::Flag::Value},
// Maildir // Maildir
{ {
@ -271,7 +296,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Maildir path for message", "Maildir path for message",
"maildir:/private/archive", "maildir:/private/archive",
'm', 'm',
MessageField::Flag::GMime | MessageField::Flag::Searchable | MessageField::Flag::GMime |
MessageField::Flag::NormalTerm |
MessageField::Flag::Value}, MessageField::Flag::Value},
// MIME // MIME
{ {
@ -281,7 +307,7 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Attachment MIME-type", "Attachment MIME-type",
"mime:image/jpeg", "mime:image/jpeg",
'y', 'y',
MessageField::Flag::Searchable}, MessageField::Flag::NormalTerm},
// Message-ID // Message-ID
{ {
MessageField::Id::MessageId, MessageField::Id::MessageId,
@ -291,7 +317,7 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"mime:image/jpeg", "mime:image/jpeg",
'i', 'i',
MessageField::Flag::GMime | MessageField::Flag::GMime |
MessageField::Flag::Searchable | MessageField::Flag::NormalTerm |
MessageField::Flag::Value}, MessageField::Flag::Value},
// Path // Path
{ {
@ -302,7 +328,7 @@ static constexpr std::array<MessageField, MessageField::id_size()>
{}, {},
'p', 'p',
MessageField::Flag::GMime | MessageField::Flag::GMime |
MessageField::Flag::XapianBoolean | MessageField::Flag::BooleanTerm |
MessageField::Flag::Value}, MessageField::Flag::Value},
// Subject // Subject
@ -314,9 +340,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"subject:wombat", "subject:wombat",
's', 's',
MessageField::Flag::GMime | MessageField::Flag::GMime |
MessageField::Flag::Searchable |
MessageField::Flag::Value | MessageField::Flag::Value |
MessageField::Flag::FullText}, MessageField::Flag::IndexableTerm},
// To // To
{ {
@ -326,19 +351,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message recipient", "Message recipient",
"to:flimflam@example.com", "to:flimflam@example.com",
't', 't',
MessageField::Flag::GMime | MessageField::Flag::Contact | MessageField::Flag::GMime |
MessageField::Flag::Value}, MessageField::Flag::Contact |
MessageField::Flag::Value
// UID (internal) },
{
MessageField::Id::Uid,
MessageField::Type::String,
"uid",
"Message recipient",
{},
'u',
MessageField::Flag::Searchable},
// References // References
{ {
MessageField::Id::References, MessageField::Id::References,
@ -347,8 +363,9 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message references to other messages", "Message references to other messages",
{}, {},
'r', 'r',
MessageField::Flag::GMime | MessageField::Flag::Value}, MessageField::Flag::GMime |
MessageField::Flag::Value
},
// Tags // Tags
{ {
MessageField::Id::Tags, MessageField::Id::Tags,
@ -357,9 +374,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message tags", "Message tags",
"tag:projectx", "tag:projectx",
'x', 'x',
MessageField::Flag::GMime | MessageField::Flag::Searchable | MessageField::Flag::GMime |
MessageField::Flag::Value}, MessageField::Flag::NormalTerm |
MessageField::Flag::Value
},
// Date // Date
{ {
MessageField::Id::Date, MessageField::Id::Date,
@ -368,10 +386,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message date", "Message date",
"date:20220101..20220505", "date:20220101..20220505",
'd', 'd',
MessageField::Flag::GMime | MessageField::Flag::Searchable | MessageField::Flag::GMime |
MessageField::Flag::Value | MessageField::Flag::XapianBoolean | MessageField::Flag::Value |
MessageField::Flag::Range}, MessageField::Flag::Range
},
// Flags // Flags
{ {
MessageField::Id::Flags, MessageField::Id::Flags,
@ -380,8 +398,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Message properties", "Message properties",
"flag:unread", "flag:unread",
'g', 'g',
MessageField::Flag::GMime | MessageField::Flag::Searchable | MessageField::Flag::GMime |
MessageField::Flag::Value}, MessageField::Flag::NormalTerm |
MessageField::Flag::Value
},
// Priority // Priority
{ {
MessageField::Id::Priority, MessageField::Id::Priority,
@ -391,9 +411,9 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"prio:high", "prio:high",
'p', 'p',
MessageField::Flag::GMime | MessageField::Flag::GMime |
MessageField::Flag::Searchable | MessageField::Flag::NormalTerm |
MessageField::Flag::Value}, MessageField::Flag::Value
},
// Size // Size
{ {
MessageField::Id::Size, MessageField::Id::Size,
@ -403,10 +423,9 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"size:1M..5M", "size:1M..5M",
'z', 'z',
MessageField::Flag::GMime | MessageField::Flag::GMime |
MessageField::Flag::Searchable |
MessageField::Flag::Value | MessageField::Flag::Value |
MessageField::Flag::Range}, MessageField::Flag::Range
},
// Mailing List // Mailing List
{ {
MessageField::Id::MailingList, MessageField::Id::MailingList,
@ -415,9 +434,10 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Mailing list (List-Id:)", "Mailing list (List-Id:)",
"list:mu-discuss.googlegroups.com", "list:mu-discuss.googlegroups.com",
'v', 'v',
MessageField::Flag::GMime | MessageField::Flag::Searchable | MessageField::Flag::GMime |
MessageField::Flag::Value}, MessageField::Flag::NormalTerm |
MessageField::Flag::Value
},
// ThreadId // ThreadId
{ {
MessageField::Id::ThreadId, MessageField::Id::ThreadId,
@ -426,7 +446,8 @@ static constexpr std::array<MessageField, MessageField::id_size()>
"Thread a message belongs to", "Thread a message belongs to",
{}, {},
'w', 'w',
MessageField::Flag::Searchable}, MessageField::Flag::NormalTerm
},
}}; }};
/* /*

View File

@ -122,7 +122,7 @@ add_field(std::vector<FieldInfo>& fields, Field::Id field_id)
return; // can't be searched return; // can't be searched
fields.emplace_back(FieldInfo{std::string{field.name}, field.xapian_term(), fields.emplace_back(FieldInfo{std::string{field.name}, field.xapian_term(),
field.is_full_text(), field_id}); field.is_indexable_term(), field_id});
} }
static std::vector<FieldInfo> static std::vector<FieldInfo>

View File

@ -36,6 +36,7 @@
#include <xapian.h> #include <xapian.h>
#include "mu-message-flags.hh" #include "mu-message-flags.hh"
#include "mu-message.hh"
#include "mu-msg.hh" #include "mu-msg.hh"
#include "mu-store.hh" #include "mu-store.hh"
#include "mu-query.hh" #include "mu-query.hh"
@ -716,13 +717,13 @@ static void
add_terms_values_str(Xapian::Document& doc, const char* val, const Field& field) add_terms_values_str(Xapian::Document& doc, const char* val, const Field& field)
{ {
const auto flat = Mu::utf8_flatten(val); const auto flat = Mu::utf8_flatten(val);
if (field.is_full_text()) { if (field.is_indexable_term()) {
Xapian::TermGenerator termgen; Xapian::TermGenerator termgen;
termgen.set_document(doc); termgen.set_document(doc);
termgen.index_text(flat, 1, field.xapian_term()); termgen.index_text(flat, 1, field.xapian_term());
} }
if (field.is_searchable()) if (field.is_normal_term())
add_term(doc, field.xapian_term(flat)); add_term(doc, field.xapian_term(flat));
} }
@ -758,7 +759,7 @@ add_terms_values_string_list(Xapian::Document& doc, MuMsg* msg, const Field& fie
g_free(str); g_free(str);
} }
if (field.is_searchable()) { if (field.is_normal_term()) {
for (; lst; lst = g_slist_next((GSList*)lst)) for (; lst; lst = g_slist_next((GSList*)lst))
add_terms_values_str(doc, (const gchar*)lst->data, field); add_terms_values_str(doc, (const gchar*)lst->data, field);
} }