mu-view: add --format=html

Support showing the HTML body (if any) instead of the default plain-text
body.

Update manpage.
This commit is contained in:
Dirk-Jan C. Binnema 2023-07-23 14:40:40 +03:00
parent 72f43f11df
commit 3337c9babb
5 changed files with 47 additions and 14 deletions

View File

@ -19,6 +19,10 @@
- what used to be the ~mu fields~ command has been merged into ~mu info~; i.e., - what used to be the ~mu fields~ command has been merged into ~mu info~; i.e.,
~mu fields~ is now ~mu info fields~. ~mu fields~ is now ~mu info fields~.
- ~mu view~ gained ~--format=html~ for it to output the HTML body of the message
rather than the (default) plain-text body. See its updated manpage for
details.
- experimental: if you build ~mu~ with [[https://github.com/CLD2Owners/cld2][CLD2]] support (available in many Linux - experimental: if you build ~mu~ with [[https://github.com/CLD2Owners/cld2][CLD2]] support (available in many Linux
distros), ~mu~ will try to detect the language of the body of e-mail distros), ~mu~ will try to detect the language of the body of e-mail
messages; you can then search by their ISO-639-1 code, e.g. ~mu find messages; you can then search by their ISO-639-1 code, e.g. ~mu find

View File

@ -15,13 +15,21 @@ mu [common options] view [options] [<file> ...]
message files and does =not= require the message to be indexed in the database. message files and does =not= require the message to be indexed in the database.
The command shows some common headers (From:, To:, Cc:, Bcc:, Subject: and The command shows some common headers (From:, To:, Cc:, Bcc:, Subject: and
Date:), the list of attachments and the plain-text body of the message (if any). Date:), the list of attachments and either the plain-text or html body of the
message (if any), or its s-expression representation.
If no message file is provided, the command expects the message on If no message file is provided, the command reads the message from
standard-input. standard-input.
* VIEW OPTIONS * VIEW OPTIONS
** --format,-o = <format>
use the given output format, one of:
- ~plain~ - use the plain-text body; this is the default
- ~html~ - use the HTML body
- ~sexp~ - show the S-expression representation of the message
** --summary-len=<number> ** --summary-len=<number>
instead of displaying the full message, output a summary based upon the first instead of displaying the full message, output a summary based upon the first
=<number>= lines of the message. =<number>= lines of the message.

View File

@ -85,29 +85,42 @@ print_field(const std::string& field, const std::string& val, bool color)
static void static void
body_or_summary(const Message& message, const Options& opts) body_or_summary(const Message& message, const Options& opts)
{ {
gboolean color; const auto color{!opts.nocolor};
using Format = Options::View::Format;
color = !opts.nocolor; std::string body, btype;
switch (opts.view.format) {
case Format::Plain:
btype = "plain text";
body = message.body_text().value_or("");
break;
case Format::Html:
btype = "html";
body = message.body_html().value_or("");
break;
default:
throw std::range_error("unsupported format"); // bug
}
const auto body{message.body_text()}; if (body.empty()) {
if (!body || body->empty()) {
if (any_of(message.flags() & Flags::Encrypted)) { if (any_of(message.flags() & Flags::Encrypted)) {
color_maybe(MU_COLOR_CYAN); color_maybe(MU_COLOR_CYAN);
mu_println("[No text body found; message has encrypted parts]"); mu_println("[No {} body found; message does have encrypted parts]",
btype);
} else { } else {
color_maybe(MU_COLOR_MAGENTA); color_maybe(MU_COLOR_MAGENTA);
mu_println("[No text body found]"); mu_println("[No {} body found]", btype);
} }
color_maybe(MU_COLOR_DEFAULT); color_maybe(MU_COLOR_DEFAULT);
return; return;
} }
if (opts.view.summary_len) { if (opts.view.summary_len) {
const auto summ{summarize(body->c_str(), *opts.view.summary_len)}; const auto summ{summarize(body, *opts.view.summary_len)};
print_field("Summary", summ, color); print_field("Summary", summ, color);
} else { } else {
mu_print_encoded("{}", *body); mu_print_encoded("{}", body);
if (!g_str_has_suffix(body->c_str(), "\n")) if (!g_str_has_suffix(body.c_str(), "\n"))
mu_println(""); mu_println("");
} }
} }
@ -131,6 +144,8 @@ view_msg_plain(const Message& message, const Options& opts)
print_field("Tags", join(message.tags(), ", "), color); print_field("Tags", join(message.tags(), ", "), color);
print_field("Attachments",get_attach_str(message, opts), color); print_field("Attachments",get_attach_str(message, opts), color);
mu_println("");
body_or_summary(message, opts); body_or_summary(message, opts);
return Ok(); return Ok();
@ -143,7 +158,9 @@ handle_msg(const Message& message, const Options& opts)
switch (opts.view.format) { switch (opts.view.format) {
case Format::Plain: case Format::Plain:
case Format::Html:
return view_msg_plain(message, opts); return view_msg_plain(message, opts);
case Format::Sexp: case Format::Sexp:
return view_msg_sexp(message, opts); return view_msg_sexp(message, opts);
default: default:
@ -173,7 +190,8 @@ Mu::mu_cmd_view(const Options& opts)
const auto msgtxt = read_from_stdin(); const auto msgtxt = read_from_stdin();
if (!msgtxt) if (!msgtxt)
return Err(msgtxt.error()); return Err(msgtxt.error());
auto message = Message::make_from_text(*msgtxt,{}, message_options(opts.view)); auto message = Message::make_from_text(*msgtxt,{},
message_options(opts.view));
if (!message) if (!message)
return Err(message.error()); return Err(message.error());
else else

View File

@ -497,10 +497,13 @@ static void
sub_view(CLI::App& sub, Options& opts) sub_view(CLI::App& sub, Options& opts)
{ {
using Format = Options::View::Format; using Format = Options::View::Format;
static constexpr InfoEnum<Format, 2> FormatInfos = {{ static constexpr InfoEnum<Format, 3> FormatInfos = {{
{ Format::Plain, { Format::Plain,
{"plain", "Plain output"} {"plain", "Plain output"}
}, },
{ Format::Html,
{"html", "Plain output with HTML body"}
},
{ Format::Sexp, { Format::Sexp,
{"sexp", "S-expressions"} {"sexp", "S-expressions"}
}, },

View File

@ -237,7 +237,7 @@ struct Options {
bool terminate; /**< add \f between msgs in view */ bool terminate; /**< add \f between msgs in view */
OptSize summary_len; /**< max # of lines for summary */ OptSize summary_len; /**< max # of lines for summary */
enum struct Format { Plain, Sexp }; enum struct Format { Plain, Sexp, Html };
Format format; /**< output format*/ Format format; /**< output format*/
StringVec files; /**< Message file(s) */ StringVec files; /**< Message file(s) */