mu: add fields/flags commands

Useful information for devising queries.

Directly generated from the source. Add manpages, too.
pull/2234/merge
Dirk-Jan C. Binnema 9 months ago
parent 30e7b5d9ec
commit 8f9d1e5e60
  1. 65
      lib/message/mu-flags.hh
  2. 2
      man/Makefile.am
  3. 2
      man/meson.build
  4. 32
      man/mu-fields.1
  5. 24
      man/mu-find.1
  6. 31
      man/mu-flags.1
  7. 33
      man/mu-query.7
  8. 1
      mu/meson.build
  9. 131
      mu/mu-cmd-fields.cc
  10. 46
      mu/mu-cmd.cc
  11. 20
      mu/mu-cmd.hh
  12. 4
      mu/mu-config.cc
  13. 2
      mu/mu-config.hh

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

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

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

@ -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)

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

@ -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)

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

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

@ -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();
}

@ -43,6 +43,8 @@
#include "utils/mu-utils.hh"
#include "message/mu-message.hh"
#include <thirdparty/tabulate.hpp>
#define VIEW_TERMINATOR '\f' /* form-feed */
using namespace Mu;
@ -467,14 +469,18 @@ cmd_verify(const MuConfig* opts)
static MuError
cmd_info(const Mu::Store& store, const MuConfig* opts, GError** err)
{
Mu::MaybeAnsi col{!opts->nocolor};
using namespace tabulate;
Table info;
//Mu::MaybeAnsi col{!opts->nocolor};
key_val(col, "maildir", store.properties().root_maildir);
key_val(col, "database-path", store.properties().database_path);
key_val(col, "schema-version", store.properties().schema_version);
key_val(col, "max-message-size", store.properties().max_message_size);
key_val(col, "batch-size", store.properties().batch_size);
key_val(col, "messages in store", store.size());
info.add_row({"maildir", store.properties().root_maildir});
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 tstamp{::localtime(&created)};
@ -485,14 +491,27 @@ cmd_info(const Mu::Store& store, const MuConfig* opts, GError** err)
strftime(tbuf, sizeof(tbuf), "%c", tstamp);
#pragma GCC diagnostic pop
key_val(col, "created", tbuf);
info.add_row({"created", tbuf});
const auto addrs{store.properties().personal_addresses};
if (addrs.empty())
key_val(col, "personal-address", "<none>");
info.add_row({"personal-address", "<none>"});
else
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;
}
@ -621,7 +640,12 @@ Mu::mu_cmd_execute(const MuConfig* opts, GError** err) try {
/*
* 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_SCRIPT: merr = mu_cmd_script(opts, err); break;
case MU_CONFIG_CMD_VIEW:

@ -45,6 +45,26 @@ Result<void> mu_cmd_find(const Mu::Store& store, 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
*

@ -443,7 +443,9 @@ cmd_from_string(const char* str)
{"info", MU_CONFIG_CMD_INFO}, {"init", MU_CONFIG_CMD_INIT},
{"mkdir", MU_CONFIG_CMD_MKDIR}, {"remove", MU_CONFIG_CMD_REMOVE},
{"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)
return MU_CONFIG_CMD_UNKNOWN;

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

Loading…
Cancel
Save