mirror of https://github.com/djcb/mu.git
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:
parent
72f43f11df
commit
3337c9babb
4
NEWS.org
4
NEWS.org
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
Loading…
Reference in New Issue