mu: add fields/flags commands

Useful information for devising queries.

Directly generated from the source. Add manpages, too.
This commit is contained in:
Dirk-Jan C. Binnema 2022-04-30 01:10:31 +03:00
parent 30e7b5d9ec
commit 8f9d1e5e60
13 changed files with 329 additions and 62 deletions

View File

@ -88,10 +88,12 @@ enum struct MessageFlagCategory {
* *
*/ */
struct MessageFlagInfo { struct MessageFlagInfo {
Flags flag; /**< The message flag */
char shortcut; /**< Shortcut character */ Flags flag; /**< The message flag */
std::string_view name; /**< Name of the flag */ char shortcut; /**< Shortcut character */
MessageFlagCategory category; /**< Flag category */ std::string_view name; /**< Name of the flag */
MessageFlagCategory category; /**< Flag category */
std::string_view description; /**< Description */
/** /**
* Get the lower-case version of shortcut * Get the lower-case version of shortcut
@ -108,24 +110,43 @@ struct MessageFlagInfo {
* Array of all flag information. * Array of all flag information.
*/ */
constexpr std::array<MessageFlagInfo, 12> AllMessageFlagInfos = {{ constexpr std::array<MessageFlagInfo, 12> AllMessageFlagInfos = {{
MessageFlagInfo{Flags::Draft, 'D', "draft", MessageFlagCategory::Mailfile}, MessageFlagInfo{Flags::Draft, 'D', "draft", MessageFlagCategory::Mailfile,
MessageFlagInfo{Flags::Flagged, 'F', "flagged", MessageFlagCategory::Mailfile}, "Draft (in progress)"
MessageFlagInfo{Flags::Passed, 'P', "passed", MessageFlagCategory::Mailfile}, },
MessageFlagInfo{Flags::Replied, 'R', "replied", MessageFlagCategory::Mailfile}, MessageFlagInfo{Flags::Flagged, 'F', "flagged", MessageFlagCategory::Mailfile,
MessageFlagInfo{Flags::Seen, 'S', "seen", MessageFlagCategory::Mailfile}, "User-flagged"
MessageFlagInfo{Flags::Trashed, 'T', "trashed", MessageFlagCategory::Mailfile}, },
MessageFlagInfo{Flags::Passed, 'P', "passed", MessageFlagCategory::Mailfile,
"Forwarded message"
},
MessageFlagInfo{Flags::Replied, 'R', "replied", MessageFlagCategory::Mailfile,
"Replied-to"
},
MessageFlagInfo{Flags::Seen, 'S', "seen", MessageFlagCategory::Mailfile,
"Viewed at least once"
},
MessageFlagInfo{Flags::Trashed, 'T', "trashed", MessageFlagCategory::Mailfile,
"Marked for deletion"
},
MessageFlagInfo{Flags::New, 'N', "new", MessageFlagCategory::Maildir,
"New message"
},
MessageFlagInfo{Flags::Signed, 'z', "signed", MessageFlagCategory::Content,
"Cryptographically signed"
},
MessageFlagInfo{Flags::Encrypted, 'x', "encrypted", MessageFlagCategory::Content,
"Encrypted"
},
MessageFlagInfo{Flags::HasAttachment,'a', "attach", MessageFlagCategory::Content,
"Has at least one attachment"
},
MessageFlagInfo{Flags::New, 'N', "new", MessageFlagCategory::Maildir}, MessageFlagInfo{Flags::Unread, 'u', "unread", MessageFlagCategory::Pseudo,
"New or not seen message"
MessageFlagInfo{Flags::Signed, 'z', "signed", MessageFlagCategory::Content}, },
MessageFlagInfo{Flags::Encrypted, 'x', "encrypted", MessageFlagInfo{Flags::MailingList, 'l', "list", MessageFlagCategory::Content,
MessageFlagCategory::Content}, "Mailing list message"
MessageFlagInfo{Flags::HasAttachment, 'a', "attach", },
MessageFlagCategory::Content},
MessageFlagInfo{Flags::Unread, 'u', "unread", MessageFlagCategory::Pseudo},
MessageFlagInfo{Flags::MailingList, 'l', "list", MessageFlagCategory::Content},
}}; }};

View File

@ -22,7 +22,9 @@ dist_man_MANS = \
mu-cfind.1 \ mu-cfind.1 \
mu-easy.1 \ mu-easy.1 \
mu-extract.1 \ mu-extract.1 \
mu-fields.1 \
mu-find.1 \ mu-find.1 \
mu-flags.1 \
mu-help.1 \ mu-help.1 \
mu-index.1 \ mu-index.1 \
mu-info.1 \ mu-info.1 \

View File

@ -21,7 +21,9 @@ install_man(
'mu-cfind.1', 'mu-cfind.1',
'mu-easy.1', 'mu-easy.1',
'mu-extract.1', 'mu-extract.1',
'mu-fields.1',
'mu-find.1', 'mu-find.1',
'mu-flags.1',
'mu-help.1', 'mu-help.1',
'mu-index.1', 'mu-index.1',
'mu-info.1', 'mu-info.1',

32
man/mu-fields.1 Normal file
View File

@ -0,0 +1,32 @@
.TH MU FIELDS 1 "April 2022" "User Manuals"
.SH NAME
mu fields\- list all message fields
.SH SYNOPSIS
.B mu fields [options]
.SH DESCRIPTION
\fBmu fields\fR is the \fBmu\fR command for showing a table of message fields
and their properties.
.SH OPTIONS
Inherits common options from
.BR mu(1)
.SH BUGS
Please report bugs if you find them:
.BR https://github.com/djcb/mu/issues
.SH AUTHOR
Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
.SH "SEE ALSO"
.BR mu (1)

View File

@ -1,4 +1,4 @@
.TH MU FIND 1 "29 January 2022" "User Manuals" .TH MU FIND 1 "29 April 2022" "User Manuals"
.SH NAME .SH NAME
@ -23,10 +23,10 @@ some search pattern. The search patterns are described in detail in
For example: For example:
.nf .nf
$ mu find subject:snow and date:2017.. $ mu find subject:snow and date:2009..
.fi .fi
would find all messages in 2017 with 'snow' in the subject field, e.g: would find all messages in 2009 with 'snow' in the subject field, e.g:
.nf .nf
2009-03-05 17:57:33 EET Lucia <lucia@example.com> running in the snow 2009-03-05 17:57:33 EET Lucia <lucia@example.com> running in the snow
@ -71,23 +71,20 @@ would list the date, subject and sender of all messages with 'snow' in the
their subject. their subject.
The table of replacement characters is superset of the list mentions for The table of replacement characters is superset of the list mentions for
search parameters; the complete list: search parameters, such as:
.nf .nf
t \fBt\fRo: recipient t \fBt\fRo: recipient
c \fBc\fRc: (carbon-copy) recipient
h Bcc: (blind carbon-copy, \fBh\fRidden) recipient
d Sent \fBd\fRate of the message d Sent \fBd\fRate of the message
f Message sender (\fBf\fRrom:) f Message sender (\fBf\fRrom:)
g Message flags (fla\fBg\fRs) g Message flags (fla\fBg\fRs)
l Full path to the message (\fBl\fRocation) l Full path to the message (\fBl\fRocation)
p Message \fBp\fRriority (high, normal, low)
s Message \fBs\fRubject s Message \fBs\fRubject
i Message-\fBi\fRd i Message-\fBi\fRd
m \fBm\fRaildir m \fBm\fRaildir
v Mailing-list Id
.fi .fi
For the complete, up-to-date list, see:
.BR mu-fields(1)
The message flags are described in \fBmu-query\fR(7). As an example, a The message flags are described in \fBmu-query\fR(7). As an example, a
message which is 'seen', has an attachment and is signed would message which is 'seen', has an attachment and is signed would
@ -97,12 +94,10 @@ message would have 'nx'.
.TP .TP
\fB\-s\fR, \fB\-\-sortfield\fR \fR=\fI<field>\fR and \fB\-z\fR, \fB\-s\fR, \fB\-\-sortfield\fR \fR=\fI<field>\fR and \fB\-z\fR,
\fB\-\-reverse\fR specifies the field to sort the search results by, and the \fB\-\-reverse\fR specifies the field to sort the search results by, and the
direction (i.e., 'reverse' means that the sort should be reverted - Z-A). The direction (i.e., 'reverse' means that the sort should be reverted - Z-A). Examples include:
following fields are supported:
.nf .nf
cc,c Cc (carbon-copy) recipient(s) cc,c Cc (carbon-copy) recipient(s)
bcc,h Bcc (blind-carbon-copy) recipient(s)
date,d Message sent date date,d Message sent date
from,f Message sender from,f Message sender
maildir,m Maildir maildir,m Maildir
@ -110,9 +105,11 @@ following fields are supported:
prio,p Nessage priority prio,p Nessage priority
subject,s Message subject subject,s Message subject
to,t To:-recipient(s) to,t To:-recipient(s)
list,v Mailing-list id
.fi .fi
For the complete, up-to-date list, see:
.BR mu-fields(1)
Thus, for example, to sort messages by date, you could specify: Thus, for example, to sort messages by date, you could specify:
.nf .nf
@ -338,3 +335,4 @@ Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
.BR mu (1), .BR mu (1),
.BR mu-index (1), .BR mu-index (1),
.BR mu-query (7) .BR mu-query (7)
.BR mu-fields (1)

31
man/mu-flags.1 Normal file
View File

@ -0,0 +1,31 @@
.TH MU FLAGS 1 "April 2022" "User Manuals"
.SH NAME
mu flags\- list all message flags
.SH SYNOPSIS
.B mu flags [options]
.SH DESCRIPTION
\fBmu flags\fR is the \fBmu\fR command for showing a table of message flags and their properties, which is useful for devising queries.
.SH OPTIONS
Inherits common options from
.BR mu(1)
.SH BUGS
Please report bugs if you find them:
.BR https://github.com/djcb/mu/issues
.SH AUTHOR
Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
.SH "SEE ALSO"
.BR mu (1)

View File

@ -1,25 +1,24 @@
.TH MU QUERY 7 "28 December 2017" "User Manuals" .TH MU QUERY 7 "22 April 2022" "User Manuals"
.SH NAME .SH NAME
mu query language \- a language for finding messages in \fBmu\fR mu query language \- a language for finding messages in \fBmu\fR databases.
databases.
.SH DESCRIPTION .SH DESCRIPTION
The mu query language is a language used by \fBmu find\fR and The mu query language is a language used by \fBmu find\fR and \fBmu4e\fR to find
\fBmu4e\fR to find messages in \fBmu\fR's Xapian databases. The messages in \fBmu\fR's Xapian databases. The language is quite similar to
language is quite similar to Xapian's default query-parser, but is an Xapian's default query-parser, but is an independent implementation that is
independent implementation that is customized for the mu/mu4e customized for the mu/mu4e use-case.
use-case.
In this article, we give a structured but informal overview of the In this article, we give a structured but informal overview of the query
query language and provide examples. language and provide examples.
\fBNOTE:\fR if you use queries on the command-line (say, for \fBmu As a companion to this, we recommend the \fBmu fields\fR command to get an up-to-date list of the available fields.
find\fR), you need to quote any characters that would otherwise be
interpreted by the shell, such as \fB""\fR, \fB(\fR and \fB)\fR and \fBNOTE:\fR if you use queries on the command-line (say, for \fBmu find\fR), you
whitespace. need to quote any characters that would otherwise be interpreted by the shell,
such as \fB""\fR, \fB(\fR and \fB)\fR and whitespace.
.de EX1 .de EX1
.nf .nf
@ -132,8 +131,7 @@ take quite a bit longer than 'normal' queries.
.SH FIELDS .SH FIELDS
We already saw a number of search fields, such as \fBsubject:\fR and We already saw a number of search fields, such as \fBsubject:\fR and
\fBbody:\fR. Here is the full table, a shortcut character and a \fBbody:\fR. Here is the full table, a shortcut character and a description.
description.
.EX1 .EX1
cc,c Cc (carbon-copy) recipient(s) cc,c Cc (carbon-copy) recipient(s)
bcc,h Bcc (blind-carbon-copy) recipient(s) bcc,h Bcc (blind-carbon-copy) recipient(s)
@ -142,6 +140,7 @@ description.
subject,s Message subject subject,s Message subject
body,b Message body body,b Message body
maildir,m Maildir maildir,m Maildir
modified,k Last modification time
msgid,i Message-ID msgid,i Message-ID
prio,p Message priority (\fIlow\fR, \fInormal\fR or \fIhigh\fR) prio,p Message priority (\fIlow\fR, \fInormal\fR or \fIhigh\fR)
flag,g Message Flags flag,g Message Flags
@ -152,6 +151,8 @@ description.
mime,y MIME-type of one or more message parts mime,y MIME-type of one or more message parts
tag,x Tags for the message tag,x Tags for the message
list,v Mailing list (e.g. the List-Id value) list,v Mailing list (e.g. the List-Id value)
The \fBmu fields\fR command is recommended to get the latest version.
.EX2 .EX2
The shortcut character can be used instead of the full name: The shortcut character can be used instead of the full name:
.EX1 .EX1

View File

@ -25,6 +25,7 @@ mu = executable(
'mu.cc', 'mu.cc',
'mu-cmd-cfind.cc', 'mu-cmd-cfind.cc',
'mu-cmd-extract.cc', 'mu-cmd-extract.cc',
'mu-cmd-fields.cc',
'mu-cmd-find.cc', 'mu-cmd-find.cc',
'mu-cmd-index.cc', 'mu-cmd-index.cc',
'mu-cmd-script.cc', 'mu-cmd-script.cc',

131
mu/mu-cmd-fields.cc Normal file
View File

@ -0,0 +1,131 @@
/*
** Copyright (C) 2022 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** This program is free software; you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free Software
** Foundation; either version 3, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
** details.
**
** You should have received a copy of the GNU General Public License along with
** this program; if not, write to the Free Software Foundation, Inc., 51
** Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**
*/
#include "mu-cmd.hh"
#include <message/mu-message.hh>
#include <iostream>
#include "mu-flags.hh"
#include "utils/mu-utils.hh"
#include "thirdparty/tabulate.hpp"
using namespace Mu;
static void
show_fields(const MuConfig* opts)
{
using namespace tabulate;
using namespace std::string_literals;
Table fields;
fields.add_row({"field-name", "alias", "short", "search",
"value", "example", "description"});
if (!opts->nocolor) {
(*fields.begin()).format()
.font_style({FontStyle::bold})
.font_color({Color::blue});
}
auto disp= [&](std::string_view sv)->std::string {
if (sv.empty())
return "";
else
return format("%*s", STR_V(sv));
};
auto searchable=[&](const Field& field)->std::string {
if (field.is_boolean_term())
return "boolean";
if (field.is_indexable_term())
return "index";
if (field.is_normal_term())
return "yes";
if (field.is_contact())
return "contact";
if (field.is_range())
return "range";
return "no";
};
size_t row{};
field_for_each([&](auto&& field){
if (field.is_internal())
return; // skip.
fields.add_row({format("%*s", STR_V(field.name)),
field.alias.empty() ? "" : format("%*s", STR_V(field.alias)),
field.shortcut ? format("%c", field.shortcut) : ""s,
searchable(field),
field.is_value() ? "yes" : "no",
disp(field.example_query),
disp(field.description)});
++row;
});
std::cout << fields << '\n';
}
static void
show_flags(const MuConfig* opts)
{
using namespace tabulate;
using namespace std::string_literals;
Table flags;
flags.add_row({"flag", "shortcut", "category", "description"});
if (!opts->nocolor) {
(*flags.begin()).format()
.font_style({FontStyle::bold})
.font_color({Color::green});
}
flag_infos_for_each([&](const MessageFlagInfo& info) {
flags.add_row({format("%*s", STR_V(info.name)),
format("%c", info.shortcut),
"<cat>"s,
std::string{info.description}});
});
std::cout << flags << '\n';
}
Result<void>
Mu::mu_cmd_fields(const MuConfig* opts)
{
g_return_val_if_fail(opts, Err(Error::Code::Internal, "no opts"));
show_fields(opts);
return Ok();
}
Result<void>
Mu::mu_cmd_flags(const MuConfig* opts)
{
g_return_val_if_fail(opts, Err(Error::Code::Internal, "no opts"));
show_flags(opts);
return Ok();
}

View File

@ -43,6 +43,8 @@
#include "utils/mu-utils.hh" #include "utils/mu-utils.hh"
#include "message/mu-message.hh" #include "message/mu-message.hh"
#include <thirdparty/tabulate.hpp>
#define VIEW_TERMINATOR '\f' /* form-feed */ #define VIEW_TERMINATOR '\f' /* form-feed */
using namespace Mu; using namespace Mu;
@ -467,14 +469,18 @@ cmd_verify(const MuConfig* opts)
static MuError static MuError
cmd_info(const Mu::Store& store, const MuConfig* opts, GError** err) cmd_info(const Mu::Store& store, const MuConfig* opts, GError** err)
{ {
Mu::MaybeAnsi col{!opts->nocolor}; using namespace tabulate;
key_val(col, "maildir", store.properties().root_maildir); Table info;
key_val(col, "database-path", store.properties().database_path);
key_val(col, "schema-version", store.properties().schema_version); //Mu::MaybeAnsi col{!opts->nocolor};
key_val(col, "max-message-size", store.properties().max_message_size);
key_val(col, "batch-size", store.properties().batch_size); info.add_row({"maildir", store.properties().root_maildir});
key_val(col, "messages in store", store.size()); info.add_row({"database-path", store.properties().database_path});
info.add_row({"schema-version", store.properties().schema_version});
info.add_row({"max-message-size", format("%zu", store.properties().max_message_size)});
info.add_row({"batch-size", format("%zu", store.properties().batch_size)});
info.add_row({"messages in store", format("%zu", store.size())});
const auto created{store.properties().created}; const auto created{store.properties().created};
const auto tstamp{::localtime(&created)}; const auto tstamp{::localtime(&created)};
@ -485,14 +491,27 @@ cmd_info(const Mu::Store& store, const MuConfig* opts, GError** err)
strftime(tbuf, sizeof(tbuf), "%c", tstamp); strftime(tbuf, sizeof(tbuf), "%c", tstamp);
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
key_val(col, "created", tbuf); info.add_row({"created", tbuf});
const auto addrs{store.properties().personal_addresses}; const auto addrs{store.properties().personal_addresses};
if (addrs.empty()) if (addrs.empty())
key_val(col, "personal-address", "<none>"); info.add_row({"personal-address", "<none>"});
else else
for (auto&& c : addrs) for (auto&& c : addrs)
key_val(col, "personal-address", c); info.add_row({"personal-address", c});
if (!opts->nocolor) {
for (auto&& row: info) {
row.cells().at(0)->format().font_style({FontStyle::bold})
.font_color({Color::green});
row.cells().at(1)->format().font_color({Color::blue});
}
}
std::cout << info << std::endl;
return MU_OK; return MU_OK;
} }
@ -621,7 +640,12 @@ Mu::mu_cmd_execute(const MuConfig* opts, GError** err) try {
/* /*
* no store needed * no store needed
*/ */
case MU_CONFIG_CMD_FIELDS:
merr = mu_error_from_result(mu_cmd_fields(opts), err);
break;
case MU_CONFIG_CMD_FLAGS:
merr = mu_error_from_result(mu_cmd_flags(opts), err);
break;
case MU_CONFIG_CMD_MKDIR: merr = cmd_mkdir(opts, err); break; case MU_CONFIG_CMD_MKDIR: merr = cmd_mkdir(opts, err); break;
case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script(opts, err); break; case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script(opts, err); break;
case MU_CONFIG_CMD_VIEW: case MU_CONFIG_CMD_VIEW:

View File

@ -45,6 +45,26 @@ Result<void> mu_cmd_find(const Mu::Store& store, const MuConfig* opts);
*/ */
Result<void> mu_cmd_extract(const MuConfig* opts); Result<void> mu_cmd_extract(const MuConfig* opts);
/**
* execute the 'fields' command
*
* @param opts configuration options
*
* @return Ok() or some error
*/
Result<void> mu_cmd_fields(const MuConfig* opts);
/**
* execute the 'flags' command
*
* @param opts configuration options
*
* @return Ok() or some error
*/
Result<void> mu_cmd_flags(const MuConfig* opts);
/** /**
* execute the 'script' command * execute the 'script' command
* *

View File

@ -443,7 +443,9 @@ cmd_from_string(const char* str)
{"info", MU_CONFIG_CMD_INFO}, {"init", MU_CONFIG_CMD_INIT}, {"info", MU_CONFIG_CMD_INFO}, {"init", MU_CONFIG_CMD_INIT},
{"mkdir", MU_CONFIG_CMD_MKDIR}, {"remove", MU_CONFIG_CMD_REMOVE}, {"mkdir", MU_CONFIG_CMD_MKDIR}, {"remove", MU_CONFIG_CMD_REMOVE},
{"script", MU_CONFIG_CMD_SCRIPT}, {"server", MU_CONFIG_CMD_SERVER}, {"script", MU_CONFIG_CMD_SCRIPT}, {"server", MU_CONFIG_CMD_SERVER},
{"verify", MU_CONFIG_CMD_VERIFY}, {"view", MU_CONFIG_CMD_VIEW}}; {"verify", MU_CONFIG_CMD_VERIFY}, {"view", MU_CONFIG_CMD_VIEW},
{"fields", MU_CONFIG_CMD_FIELDS}, {"flags", MU_CONFIG_CMD_FLAGS}
};
if (!str) if (!str)
return MU_CONFIG_CMD_UNKNOWN; return MU_CONFIG_CMD_UNKNOWN;

View File

@ -64,7 +64,9 @@ typedef enum {
MU_CONFIG_CMD_ADD, MU_CONFIG_CMD_ADD,
MU_CONFIG_CMD_CFIND, MU_CONFIG_CMD_CFIND,
MU_CONFIG_CMD_EXTRACT, MU_CONFIG_CMD_EXTRACT,
MU_CONFIG_CMD_FIELDS,
MU_CONFIG_CMD_FIND, MU_CONFIG_CMD_FIND,
MU_CONFIG_CMD_FLAGS,
MU_CONFIG_CMD_HELP, MU_CONFIG_CMD_HELP,
MU_CONFIG_CMD_INDEX, MU_CONFIG_CMD_INDEX,
MU_CONFIG_CMD_INFO, MU_CONFIG_CMD_INFO,