Re: [PATCH v3 1/2] cli/show: add --format=pretty
Thanks for reviewing the patch! On Tue, 13 Jul 2021 07:24:43 -0300, David Bremner wrote: > David Bremner writes: > > I don't know what g_mime_message_get_message_id will return if there is > > no message-id, but that case can and does arise. It returns null and the printing function prints out `(null)` IIRC so it's not a crash (I checked that), but good point nonetheless. > I expect that would require somehow making the notmuch_database_t object > available inside the sprinter. We want this for at least one other > feature request (configurable headers in json / sexpr output), so it's > not as much of a "waste" of effort as it might seem at first. That's good to know. I was afraid of making big changes for no reason. I think I had a version that added a function parameter but thought it's too ugly and complicated to submit. > The options are adding extra arguments to functions and stashing a > copy of the pointer in some struct (perhaps the sprinter struct). I'll see if I find a good way to do the latter when I have time. Thanks for the pointers! Hannu ___ notmuch mailing list -- notmuch@notmuchmail.org To unsubscribe send an email to notmuch-le...@notmuchmail.org
Re: [PATCH v3 1/2] cli/show: add --format=pretty
David Bremner writes: > > I don't know what g_mime_message_get_message_id will return if there is > no message-id, but that case can and does arise. Notmuch constructs a > message-id by sha1 hashing the message. That message-id is in the > database, so I think you should probably print out the message-id from > the database. > I expect that would require somehow making the notmuch_database_t object available inside the sprinter. We want this for at least one other feature request (configurable headers in json / sexpr output), so it's not as much of a "waste" of effort as it might seem at first. The options are adding extra arguments to functions and stashing a copy of the pointer in some struct (perhaps the sprinter struct). I think David E has a prototype of the former. My own instincts is that the latter will be more general. The previous consensus was that we did not want to add static (file scope) variables, even though that would be the quick and dirty solution. d ___ notmuch mailing list -- notmuch@notmuchmail.org To unsubscribe send an email to notmuch-le...@notmuchmail.org
Re: [PATCH v3 1/2] cli/show: add --format=pretty
Hannu Hartikainen writes: > +static notmuch_status_t > +format_part_pretty (const void *ctx, sprinter_t *sp, mime_node_t *node, > + int indent, const notmuch_show_params_t *params) > +{ > +/* The disposition and content-type metadata are associated with > + * the envelope for message parts */ > +GMimeObject *meta = node->envelope_part ? ( > + GMIME_OBJECT (node->envelope_part) ) : node->part; > +GMimeContentType *content_type = g_mime_object_get_content_type (meta); > +GMimeStream *stream = params->out_stream; > +int i; > + > +if (GMIME_IS_MESSAGE (node->part)) { > + GMimeMessage *message = GMIME_MESSAGE (node->part); > + char *recipients_string; > + char *date_string; > + > + g_mime_stream_printf (stream, "Subject: %s\n", > g_mime_message_get_subject (message)); > + g_mime_stream_printf (stream, "From: %s\n", > g_mime_message_get_from_string (message)); > + recipients_string = g_mime_message_get_address_string (message, > GMIME_ADDRESS_TYPE_TO); > + if (recipients_string) > + g_mime_stream_printf (stream, "To: %s\n", recipients_string); > + g_free (recipients_string); > + recipients_string = g_mime_message_get_address_string (message, > GMIME_ADDRESS_TYPE_CC); > + if (recipients_string) > + g_mime_stream_printf (stream, "Cc: %s\n", recipients_string); > + g_free (recipients_string); > + date_string = g_mime_message_get_date_string (node, message); > + g_mime_stream_printf (stream, "Date: %s\n", date_string); > + g_mime_stream_printf (stream, "Message-ID: <%s>\n\n", > g_mime_message_get_message_id ( > + message)); I don't know what g_mime_message_get_message_id will return if there is no message-id, but that case can and does arise. Notmuch constructs a message-id by sha1 hashing the message. That message-id is in the database, so I think you should probably print out the message-id from the database. > +static const notmuch_show_format_t format_pretty = { > +.new_sprinter = sprinter_text_create, > +.part = format_part_pretty, > +}; I think this deserves a comment to explain briefly why it works. > diff --git a/test/T520-show.sh b/test/T520-show.sh > index 6f42ca12..c9bcf81d 100755 > --- a/test/T520-show.sh > +++ b/test/T520-show.sh > @@ -27,4 +27,36 @@ notmuch show --entire-thread=true --sort=newest-first > $QUERY > EXPECTED > notmuch show --entire-thread=true --sort=oldest-first $QUERY > OUTPUT > test_expect_equal_file EXPECTED OUTPUT > > +test_begin_subtest "--format=pretty" > +output=$(notmuch show --format=pretty > id:cf0c4d610911171136h1713aa59w9cf9aa31f052a...@mail.gmail.com 2>&1 && echo > OK) > +test_expect_equal "$output" "Subject: [notmuch] preliminary FreeBSD support > +From: Alex Botero-Lowry > +To: notmuch@notmuchmail.org > +Date: Tue, 17 Nov 2009 11:36:14 -0800 > +Message-ID: > + I would prefer the cat < EXPECTED ... EOF style here rather then the multiline strings, finishing with "test_expect_equal_file EXPECTED OUTPUT". ___ notmuch mailing list -- notmuch@notmuchmail.org To unsubscribe send an email to notmuch-le...@notmuchmail.org
[PATCH v3 1/2] cli/show: add --format=pretty
This commit adds the display format `pretty`. It only shows the most important headers, similarly to `--format=text`, and only displays plaintext parts (ie. text/* but not text/html). However, compared to `--format=text` the output is kept as close to raw as possible. The rationale for this feature is twofold: 1. It is useful to be able to view messages in as human-friendly format as possible. 2. The same format should still be machine-readable, too. The email format is mostly human-readable as is. The things difficult for a human eye are the huge amount of headers that are common these days and telling different messages apart when there are many. While human readability is the main goal, another design goal was that piping the output to `git am` works, at least for individual messages sent with `git send-email`. This way the format is suitable to be used as the default, both for reading and piping output to other commands. --- NEWS | 7 completion/notmuch-completion.bash | 2 +- completion/zsh/_notmuch| 2 +- doc/man1/notmuch-show.rst | 7 +++- notmuch-show.c | 54 ++ test/T520-show.sh | 32 ++ 6 files changed, 101 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 3e776009..57826734 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,13 @@ Notmuch 0.33 (UNRELEASED) = +CLI +--- + +`notmuch show` now has `--format=pretty`, optimized for reading plain +text emails on the command line. It only shows the most important +headers and plain text parts. + Emacs - diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index 15425697..86cbbcdc 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -514,7 +514,7 @@ _notmuch_show() return ;; --format) - COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "text pretty json sexp mbox raw" -- "${cur}" ) ) return ;; --exclude|--body) diff --git a/completion/zsh/_notmuch b/completion/zsh/_notmuch index e920f10b..5cc386e2 100644 --- a/completion/zsh/_notmuch +++ b/completion/zsh/_notmuch @@ -237,7 +237,7 @@ _notmuch_search() { _notmuch_show() { _arguments -S \ '--entire-thread=[output entire threads]:show thread:(true false)' \ -'--format=[set output format]:output format:(text json sexp mbox raw)' \ +'--format=[set output format]:output format:(text pretty json sexp mbox raw)' \ '--format-version=[set output format version]:format version: ' \ '--part=[output a single decoded mime part]:part number: ' \ '--verify[verify signed MIME parts]' \ diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index 64639174..c68f0b2b 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -34,7 +34,7 @@ Supported options for **show** include the matching messages. For ``--format=json`` and ``--format=sexp`` this defaults to true. For other formats, this defaults to false. -.. option:: --format=(text|json|sexp|mbox|raw) +.. option:: --format=(text|pretty|json|sexp|mbox|raw) **text** (default for messages) The default plain-text format has all text-content MIME parts @@ -46,6 +46,11 @@ Supported options for **show** include '}'), to either open or close the component. For a multipart MIME message, these parts will be nested. + **pretty** + The plain-text parts of all matching messages are printed in a + format optimized for readability. Only the most important + headers are displayed. + **json** The output is formatted with Javascript Object Notation (JSON). This format is more robust than the text format for diff --git a/notmuch-show.c b/notmuch-show.c index c8f1a40f..69b1e697 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -606,6 +606,52 @@ format_part_text (const void *ctx, sprinter_t *sp, mime_node_t *node, return NOTMUCH_STATUS_SUCCESS; } +static notmuch_status_t +format_part_pretty (const void *ctx, sprinter_t *sp, mime_node_t *node, + int indent, const notmuch_show_params_t *params) +{ +/* The disposition and content-type metadata are associated with + * the envelope for message parts */ +GMimeObject *meta = node->envelope_part ? ( + GMIME_OBJECT (node->envelope_part) ) : node->part; +GMimeContentType *content_type = g_mime_object_get_content_type (meta); +GMimeStream *stream = params->out_stream; +int i; + +if (GMIME_IS_MESSAGE (node->part)) { + GMimeMessage *message = GMIME_MESSAGE (node->part); + char *recipients_string; + char *date_string; + + g_mime_stream_printf (stream, "Subject: %s\n", g_mime_message_get_subject (message)); + g_mime_stream_printf (stream, "From: %s\n", g_mime