[PATCH] man: show: update man page for entire-thread and json.
Previously in notmuch show --format=json implied --entire-thread. This is still the default but it is now possible to disable this. Update the manpage to reflect this. --- I didn't update the manpage in the recent patch series. This corrects that omission. (Less cumbersome wording gratefully received) Best wishes Markman/man1/notmuch-show.1 | 16 +--- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/man/man1/notmuch-show.1 b/man/man1/notmuch-show.1 index b51a54c..5fa590e 100644 --- a/man/man1/notmuch-show.1 +++ b/man/man1/notmuch-show.1 @@ -26,9 +26,9 @@ include .TP 4 .B \-\-entire\-thread -By default only those messages that match the search terms will be -displayed. With this option, all messages in the same thread as any -matched message will be displayed. +By default (except when format=json) only those messages that match +the search terms will be displayed. With this option, all messages in +the same thread as any matched message will be displayed. .RE .RS 4 @@ -55,11 +55,13 @@ be nested. The output is formatted with Javascript Object Notation (JSON). This format is more robust than the text format for automated processing. The nested structure of multipart MIME messages is -reflected in nested JSON output. JSON output always includes all -messages in a matching thread; in effect +reflected in nested JSON output. By default JSON output includes all +messages in a matching thread; that is, by default, .B \-\-format=json -implies -.B \-\-entire\-thread +sets +.B "\-\-entire\-thread" +The caller can disable this behaviour by setting +.B \-\-entire\-thread=false .RE .RS 4 -- 1.7.9.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.
On Fri, Jul 20 2012, craven at gmx.net wrote: > From: > > This patch switches from the current ad-hoc printer to the structured > formatters in sprinter.h, sprinter-text.c and sprinter-json.c. > > The JSON tests are changed slightly in order to make them PASS for the > new structured output formatter. > > The text tests pass without adaptation. > --- > notmuch-search.c | 301 > --- > test/json| 34 --- > 2 files changed, 103 insertions(+), 232 deletions(-) > > diff --git a/notmuch-search.c b/notmuch-search.c > index 3be296d..07211e8 100644 > --- a/notmuch-search.c > +++ b/notmuch-search.c > @@ -19,6 +19,7 @@ > */ > > #include "notmuch-client.h" > +#include "sprinter.h" > > typedef enum { > OUTPUT_SUMMARY, > @@ -28,92 +29,6 @@ typedef enum { > OUTPUT_TAGS > } output_t; > > -typedef struct search_format { > -const char *results_start; > -const char *item_start; > -void (*item_id) (const void *ctx, > - const char *item_type, > - const char *item_id); > -void (*thread_summary) (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject); > -const char *tag_start; > -const char *tag; > -const char *tag_sep; > -const char *tag_end; > -const char *item_sep; > -const char *item_end; > -const char *results_end; > -const char *results_null; > -} search_format_t; > - > -static void > -format_item_id_text (const void *ctx, > - const char *item_type, > - const char *item_id); > - > -static void > -format_thread_text (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject); > -static const search_format_t format_text = { > -"", > - "", > - format_item_id_text, > - format_thread_text, > - " (", > - "%s", " ", > - ")", "\n", > - "", > -"\n", > -"", > -}; > - > -static void > -format_item_id_json (const void *ctx, > - const char *item_type, > - const char *item_id); > - > -static void > -format_thread_json (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject); > - > -/* Any changes to the JSON format should be reflected in the file > - * devel/schemata. */ > -static const search_format_t format_json = { > -"[", > - "{", > - format_item_id_json, > - format_thread_json, > - "\"tags\": [", > - "\"%s\"", ", ", > - "]", ",\n", > - "}", > -"]\n", > -"]\n", > -}; > - > -static void > -format_item_id_text (unused (const void *ctx), > - const char *item_type, > - const char *item_id) > -{ > -printf ("%s%s", item_type, item_id); > -} > - > static char * > sanitize_string (const void *ctx, const char *str) > { > @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str) > return out; > } > > -static void > -format_thread_text (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject) > -{ > -void *ctx_quote = talloc_new (ctx); > - > -printf ("thread:%s %12s [%d/%d] %s; %s", > - thread_id, > - notmuch_time_relative_date (ctx, date), > - matched, > - total, > - sanitize_string (ctx_quote, authors), > - sanitize_string (ctx_quote, subject)); > - > -talloc_free (ctx_quote); > -} > - > -static void > -format_item_id_json (const void *ctx, > - unused (const char *item_type), > - const char *item_id) > -{ > -void *ctx_quote = talloc_new (ctx); > - > -printf ("%s", json_quote_str (ctx_quote, item_id)); > - > -talloc_free (ctx_quote); > - > -} > - > -static void > -format_thread_json (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject) > -{ > -void *ctx_quote = talloc_new (ctx); > - > -printf ("\"thread\": %s,\n" > - "\"timestamp\": %ld,\n" > - "\"date_rela
[PATCH v7 1/3] Add support for structured output formatters.
On Fri, Jul 20 2012, craven at gmx.net wrote: > From: > > This patch adds a new struct type sprinter_t, which is used for > structured formatting, e.g. JSON or S-Expressions. The structure printer > is heavily based on code from Austin Clements > (id:87d34hsdx8.fsf at awakening.csail.mit.edu). > > It includes the following functions: > > /* Start a new map/dictionary structure. This should be followed by > * a sequence of alternating calls to map_key and one of the > * value-printing functions until the map is ended by end. > */ > void (*begin_map) (struct sprinter *); > > /* Start a new list/array structure. > */ > void (*begin_list) (struct sprinter *); > > /* End the last opened list or map structure. > */ > void (*end) (struct sprinter *); > > /* Print one string/integer/boolean/null element (possibly inside a > * list or map, followed or preceded by separators). > * For string, the char * must be UTF-8 encoded. > */ > void (*string) (struct sprinter *, const char *); > void (*integer) (struct sprinter *, int); > void (*boolean) (struct sprinter *, notmuch_bool_t); > void (*null) (struct sprinter *); > > /* Print the key of a map's key/value pair. The char * must be UTF-8 > * encoded. > */ > void (*map_key) (struct sprinter *, const char *); > > /* Insert a separator (usually extra whitespace) for improved > * readability without affecting the abstract syntax of the > * structure being printed. > * For JSON, this could simply be a line break. > */ > void (*separator) (struct sprinter *); > > /* Set the current string prefix. This only affects the text > * printer, which will print this string, followed by a colon, > * before any string. For other printers, this does nothing. > */ > void (*set_prefix) (struct sprinter *, const char *); The above block duplicated below. Otherwise this LGTM. I presume the patch 3/3 emails id:"1342766173-1344-4-git-send-email-craven at gmx.net" id:"1342772624-23329-1-git-send-email-craven at gmx.net" have identical content ? > To support the plain text format properly, the following additional > function must also be implemented: > > /* Set the current string prefix. This only affects the text > * printer, which will print this string, followed by a colon, > * before any string. For other printers, this does nothing. > */ > void (*set_prefix) (struct sprinter *, const char *); > > The structure also contains a flag that should be set to FALSE in all > custom printers and to TRUE in the plain text formatter. > > /* True if this is the special-cased plain text printer. > */ > notmuch_bool_t is_text_printer; > > The printer can (and should) use internal state to insert delimiters > and syntax at the correct places. > > Example: > > format->begin_map(format); > format->map_key(format, "foo"); > format->begin_list(format); > format->integer(format, 1); > format->integer(format, 2); > format->integer(format, 3); > format->end(format); > format->map_key(format, "bar"); > format->begin_map(format); > format->map_key(format, "baaz"); > format->string(format, "hello world"); > format->end(format); > format->end(format); > > would output JSON as follows: > > {"foo": [1, 2, 3], "bar": { "baaz": "hello world"}} > --- > sprinter.h | 58 ++ > 1 file changed, 58 insertions(+) > create mode 100644 sprinter.h > > diff --git a/sprinter.h b/sprinter.h > new file mode 100644 > index 000..77dc26f > --- /dev/null > +++ b/sprinter.h > @@ -0,0 +1,58 @@ > +#ifndef NOTMUCH_SPRINTER_H > +#define NOTMUCH_SPRINTER_H > + > +/* Necessary for notmuch_bool_t */ > +#include "notmuch-client.h" > + > +/* Structure printer interface. This is used to create output > + * structured as maps (with key/value pairs), lists and primitives > + * (strings, integers and booleans). > + */ > +typedef struct sprinter { > +/* Start a new map/dictionary structure. This should be followed by > + * a sequence of alternating calls to map_key and one of the > + * value-printing functions until the map is ended by end. > + */ > +void (*begin_map) (struct sprinter *); > + > +/* Start a new list/array structure. > + */ > +void (*begin_list) (struct sprinter *); > + > +/* End the last opened list or map structure. > + */ > +void (*end) (struct sprinter *); > + > +/* Print one string/integer/boolean/null element (possibly inside a > + * list or map, followed or preceded by separators). > + * For string, the char * must be UTF-8 encoded. > + */ > +void (*string) (struct sprinter *, const char *); > +void (*integer) (struct sprinter *, int); > +void (*boolean) (struct sprinter *, notmuch_bool_t); > +void (*null) (struct sprinter *); > + > +/* Print the key of a map's key/value pair. The char * must be UT
[PATCH v7 1/3] Add support for structured output formatters.
> I presume the patch 3/3 emails > > id:"1342766173-1344-4-git-send-email-craven at gmx.net" > id:"1342772624-23329-1-git-send-email-craven at gmx.net" > > have identical content ? Yes, they do, there was a problem with the Content-Type header having ^P^P, so I re-sent correctly, but the actual e-mail content is exactly the same. Greetings, Peter
bug in parsing?
On Fri, 15 Jun 2012, David Belohrad wrote: > Dear all, > > recently I got an email from matplotlib list, which fails to parse in > notmuch-saved-search-unread. > It looks like this: > > Yest. 21:04 [3/5] Jesse Rosenthal, Tomi Ollila [PATCHv2] emacs: derive > correct timestamp in FCC unique name (inbox notmuch) > Yest. 20:58 [1/1] Allin Cottrell mouse and update 23.4 -> 24.1 > (emacs inbox) > Yest. 20:56 [3/6] Milan Kratochv?l, Jaroslav Lukesh, David Obdrzalek, > Pavel Kutina [OT:] Javascript alert jinak (hw inbox) > Error: Unexpected output from notmuch search: > thread:6a68 Yest. 20:39 [1/1] R. O'Gara; [Matplotlib-users] > (no subject) (matplotlib mightread unread) > > Yest. 19:38 [1/1] Baaba Maal - Avaaz. org Stop the African hunger games > (inbox unread) > Yest. 19:27 [1/2] Bob Proulx, sariatucla at Safe-mail.net next-line > at window end without recenter (deleted emacs inbox unread) > Yest. 19:12 [1/12] Ji?? Ku?era, hutta.j at seznam.cz, balu at home, Pavel > Hudecek LCR meter - konstrukce (deleted hw inbox unread) > > > > It seems that the weird characted in sender does it. Should those > characters be somehow escaped? This should be fixed in master, as of 9c5ea07c.
[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.
From: This patch switches from the current ad-hoc printer to the structured formatters in sprinter.h, sprinter-text.c and sprinter-json.c. The JSON tests are changed slightly in order to make them PASS for the new structured output formatter. The text tests pass without adaptation. --- notmuch-search.c | 301 --- test/json| 34 --- 2 files changed, 103 insertions(+), 232 deletions(-) diff --git a/notmuch-search.c b/notmuch-search.c index 3be296d..07211e8 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -19,6 +19,7 @@ */ #include "notmuch-client.h" +#include "sprinter.h" typedef enum { OUTPUT_SUMMARY, @@ -28,92 +29,6 @@ typedef enum { OUTPUT_TAGS } output_t; -typedef struct search_format { -const char *results_start; -const char *item_start; -void (*item_id) (const void *ctx, -const char *item_type, -const char *item_id); -void (*thread_summary) (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); -const char *tag_start; -const char *tag; -const char *tag_sep; -const char *tag_end; -const char *item_sep; -const char *item_end; -const char *results_end; -const char *results_null; -} search_format_t; - -static void -format_item_id_text (const void *ctx, -const char *item_type, -const char *item_id); - -static void -format_thread_text (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); -static const search_format_t format_text = { -"", - "", - format_item_id_text, - format_thread_text, - " (", - "%s", " ", - ")", "\n", - "", -"\n", -"", -}; - -static void -format_item_id_json (const void *ctx, -const char *item_type, -const char *item_id); - -static void -format_thread_json (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); - -/* Any changes to the JSON format should be reflected in the file - * devel/schemata. */ -static const search_format_t format_json = { -"[", - "{", - format_item_id_json, - format_thread_json, - "\"tags\": [", - "\"%s\"", ", ", - "]", ",\n", - "}", -"]\n", -"]\n", -}; - -static void -format_item_id_text (unused (const void *ctx), -const char *item_type, -const char *item_id) -{ -printf ("%s%s", item_type, item_id); -} - static char * sanitize_string (const void *ctx, const char *str) { @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str) return out; } -static void -format_thread_text (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("thread:%s %12s [%d/%d] %s; %s", - thread_id, - notmuch_time_relative_date (ctx, date), - matched, - total, - sanitize_string (ctx_quote, authors), - sanitize_string (ctx_quote, subject)); - -talloc_free (ctx_quote); -} - -static void -format_item_id_json (const void *ctx, -unused (const char *item_type), -const char *item_id) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("%s", json_quote_str (ctx_quote, item_id)); - -talloc_free (ctx_quote); - -} - -static void -format_thread_json (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("\"thread\": %s,\n" - "\"timestamp\": %ld,\n" - "\"date_relative\": \"%s\",\n" - "\"matched\": %d,\n" - "\"total\": %d,\n" - "\"authors\": %s,\n" - "\"subject\": %s,\n", - json_quote_str (ctx_quote, thread_id), - date, - notmuch_time_relative_date (ctx, date),
[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.
From: This patch switches from the current ad-hoc printer to the structured formatters in sprinter.h, sprinter-text.c and sprinter-json.c. The JSON tests are changed slightly in order to make them PASS for the new structured output formatter. The text tests pass without adaptation. --- notmuch-search.c | 301 --- test/json| 34 --- 2 files changed, 103 insertions(+), 232 deletions(-) diff --git a/notmuch-search.c b/notmuch-search.c index 3be296d..07211e8 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -19,6 +19,7 @@ */ #include "notmuch-client.h" +#include "sprinter.h" typedef enum { OUTPUT_SUMMARY, @@ -28,92 +29,6 @@ typedef enum { OUTPUT_TAGS } output_t; -typedef struct search_format { -const char *results_start; -const char *item_start; -void (*item_id) (const void *ctx, -const char *item_type, -const char *item_id); -void (*thread_summary) (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); -const char *tag_start; -const char *tag; -const char *tag_sep; -const char *tag_end; -const char *item_sep; -const char *item_end; -const char *results_end; -const char *results_null; -} search_format_t; - -static void -format_item_id_text (const void *ctx, -const char *item_type, -const char *item_id); - -static void -format_thread_text (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); -static const search_format_t format_text = { -"", - "", - format_item_id_text, - format_thread_text, - " (", - "%s", " ", - ")", "\n", - "", -"\n", -"", -}; - -static void -format_item_id_json (const void *ctx, -const char *item_type, -const char *item_id); - -static void -format_thread_json (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); - -/* Any changes to the JSON format should be reflected in the file - * devel/schemata. */ -static const search_format_t format_json = { -"[", - "{", - format_item_id_json, - format_thread_json, - "\"tags\": [", - "\"%s\"", ", ", - "]", ",\n", - "}", -"]\n", -"]\n", -}; - -static void -format_item_id_text (unused (const void *ctx), -const char *item_type, -const char *item_id) -{ -printf ("%s%s", item_type, item_id); -} - static char * sanitize_string (const void *ctx, const char *str) { @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str) return out; } -static void -format_thread_text (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("thread:%s %12s [%d/%d] %s; %s", - thread_id, - notmuch_time_relative_date (ctx, date), - matched, - total, - sanitize_string (ctx_quote, authors), - sanitize_string (ctx_quote, subject)); - -talloc_free (ctx_quote); -} - -static void -format_item_id_json (const void *ctx, -unused (const char *item_type), -const char *item_id) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("%s", json_quote_str (ctx_quote, item_id)); - -talloc_free (ctx_quote); - -} - -static void -format_thread_json (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("\"thread\": %s,\n" - "\"timestamp\": %ld,\n" - "\"date_relative\": \"%s\",\n" - "\"matched\": %d,\n" - "\"total\": %d,\n" - "\"authors\": %s,\n" - "\"subject\": %s,\n", - json_quote_str (ctx_quote, thread_id), - date, - notmuch_time_relative_date (ctx, date),
[PATCH v7 2/3] Add structured output formatter for JSON and plain text (but don't use them yet).
From: Using the new structured printer support in sprinter.h, implement sprinter_json_create, which returns a new JSON structured output formatter. The formatter prints output similar to the existing JSON, but with differences in whitespace (mostly newlines, --output=summary prints the entire message summary on one line, not split across multiple lines). Also implement a "structured" formatter for plain text that prints prefixed strings, to be used with notmuch-search.c plain text output. --- Makefile.local | 2 + sprinter-json.c | 185 sprinter-text.c | 126 ++ sprinter.h | 10 +++ 4 files changed, 323 insertions(+) create mode 100644 sprinter-json.c create mode 100644 sprinter-text.c diff --git a/Makefile.local b/Makefile.local index a890df2..296995d 100644 --- a/Makefile.local +++ b/Makefile.local @@ -290,6 +290,8 @@ notmuch_client_srcs = \ notmuch-show.c \ notmuch-tag.c \ notmuch-time.c \ + sprinter-json.c \ + sprinter-text.c \ query-string.c \ mime-node.c \ crypto.c\ diff --git a/sprinter-json.c b/sprinter-json.c new file mode 100644 index 000..32daa5a --- /dev/null +++ b/sprinter-json.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include "sprinter.h" + +struct sprinter_json { +struct sprinter vtable; +FILE *stream; +/* Top of the state stack, or NULL if the printer is not currently + * inside any aggregate types. */ +struct json_state *state; + +/* A flag to signify that a separator should be inserted in the + * output as soon as possible. + */ +notmuch_bool_t insert_separator; +}; + +struct json_state { +struct json_state *parent; +/* True if nothing has been printed in this aggregate yet. + * Suppresses the comma before a value. */ +notmuch_bool_t first; +/* The character that closes the current aggregate. */ +char close; +}; + +/* Helper function to set up the stream to print a value. If this + * value follows another value, prints a comma. */ +static struct sprinter_json * +json_begin_value (struct sprinter *sp) +{ +struct sprinter_json *spj = (struct sprinter_json *) sp; + +if (spj->state) { + if (! spj->state->first) { + fputc (',', spj->stream); + if (spj->insert_separator) { + fputc ('\n', spj->stream); + spj->insert_separator = FALSE; + } else + fputc (' ', spj->stream); + } else + spj->state->first = FALSE; +} +return spj; +} + +/* Helper function to begin an aggregate type. Prints the open + * character and pushes a new state frame. */ +static void +json_begin_aggregate (struct sprinter *sp, char open, char close) +{ +struct sprinter_json *spj = json_begin_value (sp); +struct json_state *state = talloc (spj, struct json_state); + +fputc (open, spj->stream); +state->parent = spj->state; +state->first = TRUE; +state->close = close; +spj->state = state; +} + +static void +json_begin_map (struct sprinter *sp) +{ +json_begin_aggregate (sp, '{', '}'); +} + +static void +json_begin_list (struct sprinter *sp) +{ +json_begin_aggregate (sp, '[', ']'); +} + +static void +json_end (struct sprinter *sp) +{ +struct sprinter_json *spj = (struct sprinter_json *) sp; +struct json_state *state = spj->state; + +fputc (spj->state->close, spj->stream); +spj->state = state->parent; +talloc_free (state); +if (spj->state == NULL) + fputc ('\n', spj->stream); +} + +static void +json_string (struct sprinter *sp, const char *val) +{ +static const char *const escapes[] = { + ['\"'] = "\\\"", ['\\'] = "", ['\b'] = "\\b", + ['\f'] = "\\f", ['\n'] = "\\n", ['\t'] = "\\t" +}; +struct sprinter_json *spj = json_begin_value (sp); + +fputc ('"', spj->stream); +for (; *val; ++val) { + unsigned char ch = *val; + if (ch < ARRAY_SIZE (escapes) && escapes[ch]) + fputs (escapes[ch], spj->stream); + else if (ch >= 32) + fputc (ch, spj->stream); + else + fprintf (spj->stream, "\\u%04x", ch); +} +fputc ('"', spj->stream); +} + +static void +json_integer (struct sprinter *sp, int val) +{ +struct sprinter_json *spj = json_begin_value (sp); + +fprintf (spj->stream, "%d", val); +} + +static void +json_boolean (struct sprinter *sp, notmuch_bool_t val) +{ +struct sprinter_json *spj = json_begin_value (sp); + +fputs (val ? "true" : "false", spj->stream); +} + +static void +json_null (struct sprinter *sp) +{ +struct sprinter_json *spj = json_begin_value (sp); + +fputs ("null", spj->stream); +} + +static void +json_map_key (struct sprinter *sp, const char *key) +{ +struct sprinter_json *spj = (struct sprinter_js
[PATCH v7 1/3] Add support for structured output formatters.
From: This patch adds a new struct type sprinter_t, which is used for structured formatting, e.g. JSON or S-Expressions. The structure printer is heavily based on code from Austin Clements (id:87d34hsdx8.fsf at awakening.csail.mit.edu). It includes the following functions: /* Start a new map/dictionary structure. This should be followed by * a sequence of alternating calls to map_key and one of the * value-printing functions until the map is ended by end. */ void (*begin_map) (struct sprinter *); /* Start a new list/array structure. */ void (*begin_list) (struct sprinter *); /* End the last opened list or map structure. */ void (*end) (struct sprinter *); /* Print one string/integer/boolean/null element (possibly inside a * list or map, followed or preceded by separators). * For string, the char * must be UTF-8 encoded. */ void (*string) (struct sprinter *, const char *); void (*integer) (struct sprinter *, int); void (*boolean) (struct sprinter *, notmuch_bool_t); void (*null) (struct sprinter *); /* Print the key of a map's key/value pair. The char * must be UTF-8 * encoded. */ void (*map_key) (struct sprinter *, const char *); /* Insert a separator (usually extra whitespace) for improved * readability without affecting the abstract syntax of the * structure being printed. * For JSON, this could simply be a line break. */ void (*separator) (struct sprinter *); /* Set the current string prefix. This only affects the text * printer, which will print this string, followed by a colon, * before any string. For other printers, this does nothing. */ void (*set_prefix) (struct sprinter *, const char *); To support the plain text format properly, the following additional function must also be implemented: /* Set the current string prefix. This only affects the text * printer, which will print this string, followed by a colon, * before any string. For other printers, this does nothing. */ void (*set_prefix) (struct sprinter *, const char *); The structure also contains a flag that should be set to FALSE in all custom printers and to TRUE in the plain text formatter. /* True if this is the special-cased plain text printer. */ notmuch_bool_t is_text_printer; The printer can (and should) use internal state to insert delimiters and syntax at the correct places. Example: format->begin_map(format); format->map_key(format, "foo"); format->begin_list(format); format->integer(format, 1); format->integer(format, 2); format->integer(format, 3); format->end(format); format->map_key(format, "bar"); format->begin_map(format); format->map_key(format, "baaz"); format->string(format, "hello world"); format->end(format); format->end(format); would output JSON as follows: {"foo": [1, 2, 3], "bar": { "baaz": "hello world"}} --- sprinter.h | 58 ++ 1 file changed, 58 insertions(+) create mode 100644 sprinter.h diff --git a/sprinter.h b/sprinter.h new file mode 100644 index 000..77dc26f --- /dev/null +++ b/sprinter.h @@ -0,0 +1,58 @@ +#ifndef NOTMUCH_SPRINTER_H +#define NOTMUCH_SPRINTER_H + +/* Necessary for notmuch_bool_t */ +#include "notmuch-client.h" + +/* Structure printer interface. This is used to create output + * structured as maps (with key/value pairs), lists and primitives + * (strings, integers and booleans). + */ +typedef struct sprinter { +/* Start a new map/dictionary structure. This should be followed by + * a sequence of alternating calls to map_key and one of the + * value-printing functions until the map is ended by end. + */ +void (*begin_map) (struct sprinter *); + +/* Start a new list/array structure. + */ +void (*begin_list) (struct sprinter *); + +/* End the last opened list or map structure. + */ +void (*end) (struct sprinter *); + +/* Print one string/integer/boolean/null element (possibly inside a + * list or map, followed or preceded by separators). + * For string, the char * must be UTF-8 encoded. + */ +void (*string) (struct sprinter *, const char *); +void (*integer) (struct sprinter *, int); +void (*boolean) (struct sprinter *, notmuch_bool_t); +void (*null) (struct sprinter *); + +/* Print the key of a map's key/value pair. The char * must be UTF-8 + * encoded. + */ +void (*map_key) (struct sprinter *, const char *); + +/* Insert a separator (usually extra whitespace) for improved + * readability without affecting the abstract syntax of the + * structure being printed. + * For JSON, this could simply be a line break. + */ +void (*separator) (struct sprinter *); + +/* Set the current string prefix. This only affects the text + * printer, which will print this string, followed by a colon, + * before any string. F
notmuch-reply: Structured Formatters
Currently there is no easy way to add support for different structured formatters (like JSON). For example, adding support for S-Expressions would result in code duplication. This patch series amends the situation by introducing structured formatters, which allow different implementations of structures like lists, maps, strings and numbers. The new code in sprinter.h and sprinter-json.c can be used instead of the current ad-hoc output in all parts of notmuch, a patch for notmuch-search.c is included. In a later patch, all other parts of notmuch should be adapted to the structured formatters, and the creation of formatters should be centralised (to make adding new formatters easier). A "structured" formatter is provided for notmuch-search that prints the current text format. This removes almost all the special-casing from notmuch-search.c. Overall diff --stat: Makefile.local | 2 + notmuch-search.c | 301 +-- sprinter-json.c | 185 + sprinter-text.c | 126 sprinter.h | 68 +++ test/json| 34 +++--- 6 files changed, 484 insertions(+), 232 deletions(-) Changes versus v6 of this patch: - is_text_printer is now a field, not a function. - minor formatting - sprinter_text_search has been renamed to sprinter_text (as it contains no search-specific code). - string sanitization removed from sprinter_text, the caller should sanitize the strings.
Re: bug in parsing?
On Fri, 15 Jun 2012, David Belohrad wrote: > Dear all, > > recently I got an email from matplotlib list, which fails to parse in > notmuch-saved-search-unread. > It looks like this: > > Yest. 21:04 [3/5] Jesse Rosenthal, Tomi Ollila [PATCHv2] emacs: derive > correct timestamp in FCC unique name (inbox notmuch) > Yest. 20:58 [1/1] Allin Cottrell mouse and update 23.4 -> 24.1 > (emacs inbox) > Yest. 20:56 [3/6] Milan Kratochvíl, Jaroslav Lukesh, David Obdrzalek, > Pavel Kutina [OT:] Javascript alert jinak (hw inbox) > Error: Unexpected output from notmuch search: > thread:6a68 Yest. 20:39 [1/1] R. O'Gara; [Matplotlib-users] > (no subject) (matplotlib mightread unread) > > Yest. 19:38 [1/1] Baaba Maal - Avaaz. org Stop the African hunger games > (inbox unread) > Yest. 19:27 [1/2] Bob Proulx, sariatu...@safe-mail.net next-line at > window end without recenter (deleted emacs inbox unread) > Yest. 19:12 [1/12] Jiří Kučera, hutt...@seznam.cz, balu@home, Pavel > Hudecek LCR meter - konstrukce (deleted hw inbox unread) > > > > It seems that the weird characted in sender does it. Should those > characters be somehow escaped? This should be fixed in master, as of 9c5ea07c. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v7 3/3] Use the structured formatters in notmuch-search.c.
On Fri, Jul 20 2012, cra...@gmx.net wrote: > From: > > This patch switches from the current ad-hoc printer to the structured > formatters in sprinter.h, sprinter-text.c and sprinter-json.c. > > The JSON tests are changed slightly in order to make them PASS for the > new structured output formatter. > > The text tests pass without adaptation. > --- > notmuch-search.c | 301 > --- > test/json| 34 --- > 2 files changed, 103 insertions(+), 232 deletions(-) > > diff --git a/notmuch-search.c b/notmuch-search.c > index 3be296d..07211e8 100644 > --- a/notmuch-search.c > +++ b/notmuch-search.c > @@ -19,6 +19,7 @@ > */ > > #include "notmuch-client.h" > +#include "sprinter.h" > > typedef enum { > OUTPUT_SUMMARY, > @@ -28,92 +29,6 @@ typedef enum { > OUTPUT_TAGS > } output_t; > > -typedef struct search_format { > -const char *results_start; > -const char *item_start; > -void (*item_id) (const void *ctx, > - const char *item_type, > - const char *item_id); > -void (*thread_summary) (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject); > -const char *tag_start; > -const char *tag; > -const char *tag_sep; > -const char *tag_end; > -const char *item_sep; > -const char *item_end; > -const char *results_end; > -const char *results_null; > -} search_format_t; > - > -static void > -format_item_id_text (const void *ctx, > - const char *item_type, > - const char *item_id); > - > -static void > -format_thread_text (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject); > -static const search_format_t format_text = { > -"", > - "", > - format_item_id_text, > - format_thread_text, > - " (", > - "%s", " ", > - ")", "\n", > - "", > -"\n", > -"", > -}; > - > -static void > -format_item_id_json (const void *ctx, > - const char *item_type, > - const char *item_id); > - > -static void > -format_thread_json (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject); > - > -/* Any changes to the JSON format should be reflected in the file > - * devel/schemata. */ > -static const search_format_t format_json = { > -"[", > - "{", > - format_item_id_json, > - format_thread_json, > - "\"tags\": [", > - "\"%s\"", ", ", > - "]", ",\n", > - "}", > -"]\n", > -"]\n", > -}; > - > -static void > -format_item_id_text (unused (const void *ctx), > - const char *item_type, > - const char *item_id) > -{ > -printf ("%s%s", item_type, item_id); > -} > - > static char * > sanitize_string (const void *ctx, const char *str) > { > @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str) > return out; > } > > -static void > -format_thread_text (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject) > -{ > -void *ctx_quote = talloc_new (ctx); > - > -printf ("thread:%s %12s [%d/%d] %s; %s", > - thread_id, > - notmuch_time_relative_date (ctx, date), > - matched, > - total, > - sanitize_string (ctx_quote, authors), > - sanitize_string (ctx_quote, subject)); > - > -talloc_free (ctx_quote); > -} > - > -static void > -format_item_id_json (const void *ctx, > - unused (const char *item_type), > - const char *item_id) > -{ > -void *ctx_quote = talloc_new (ctx); > - > -printf ("%s", json_quote_str (ctx_quote, item_id)); > - > -talloc_free (ctx_quote); > - > -} > - > -static void > -format_thread_json (const void *ctx, > - const char *thread_id, > - const time_t date, > - const int matched, > - const int total, > - const char *authors, > - const char *subject) > -{ > -void *ctx_quote = talloc_new (ctx); > - > -printf ("\"thread\": %s,\n" > - "\"timestamp\": %ld,\n" > - "\"date_relativ
Re: [PATCH v7 1/3] Add support for structured output formatters.
> I presume the patch 3/3 emails > > id:"1342766173-1344-4-git-send-email-cra...@gmx.net" > id:"1342772624-23329-1-git-send-email-cra...@gmx.net" > > have identical content ? Yes, they do, there was a problem with the Content-Type header having ^P^P, so I re-sent correctly, but the actual e-mail content is exactly the same. Greetings, Peter ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v7 1/3] Add support for structured output formatters.
On Fri, Jul 20 2012, cra...@gmx.net wrote: > From: > > This patch adds a new struct type sprinter_t, which is used for > structured formatting, e.g. JSON or S-Expressions. The structure printer > is heavily based on code from Austin Clements > (id:87d34hsdx8@awakening.csail.mit.edu). > > It includes the following functions: > > /* Start a new map/dictionary structure. This should be followed by > * a sequence of alternating calls to map_key and one of the > * value-printing functions until the map is ended by end. > */ > void (*begin_map) (struct sprinter *); > > /* Start a new list/array structure. > */ > void (*begin_list) (struct sprinter *); > > /* End the last opened list or map structure. > */ > void (*end) (struct sprinter *); > > /* Print one string/integer/boolean/null element (possibly inside a > * list or map, followed or preceded by separators). > * For string, the char * must be UTF-8 encoded. > */ > void (*string) (struct sprinter *, const char *); > void (*integer) (struct sprinter *, int); > void (*boolean) (struct sprinter *, notmuch_bool_t); > void (*null) (struct sprinter *); > > /* Print the key of a map's key/value pair. The char * must be UTF-8 > * encoded. > */ > void (*map_key) (struct sprinter *, const char *); > > /* Insert a separator (usually extra whitespace) for improved > * readability without affecting the abstract syntax of the > * structure being printed. > * For JSON, this could simply be a line break. > */ > void (*separator) (struct sprinter *); > > /* Set the current string prefix. This only affects the text > * printer, which will print this string, followed by a colon, > * before any string. For other printers, this does nothing. > */ > void (*set_prefix) (struct sprinter *, const char *); The above block duplicated below. Otherwise this LGTM. I presume the patch 3/3 emails id:"1342766173-1344-4-git-send-email-cra...@gmx.net" id:"1342772624-23329-1-git-send-email-cra...@gmx.net" have identical content ? > To support the plain text format properly, the following additional > function must also be implemented: > > /* Set the current string prefix. This only affects the text > * printer, which will print this string, followed by a colon, > * before any string. For other printers, this does nothing. > */ > void (*set_prefix) (struct sprinter *, const char *); > > The structure also contains a flag that should be set to FALSE in all > custom printers and to TRUE in the plain text formatter. > > /* True if this is the special-cased plain text printer. > */ > notmuch_bool_t is_text_printer; > > The printer can (and should) use internal state to insert delimiters > and syntax at the correct places. > > Example: > > format->begin_map(format); > format->map_key(format, "foo"); > format->begin_list(format); > format->integer(format, 1); > format->integer(format, 2); > format->integer(format, 3); > format->end(format); > format->map_key(format, "bar"); > format->begin_map(format); > format->map_key(format, "baaz"); > format->string(format, "hello world"); > format->end(format); > format->end(format); > > would output JSON as follows: > > {"foo": [1, 2, 3], "bar": { "baaz": "hello world"}} > --- > sprinter.h | 58 ++ > 1 file changed, 58 insertions(+) > create mode 100644 sprinter.h > > diff --git a/sprinter.h b/sprinter.h > new file mode 100644 > index 000..77dc26f > --- /dev/null > +++ b/sprinter.h > @@ -0,0 +1,58 @@ > +#ifndef NOTMUCH_SPRINTER_H > +#define NOTMUCH_SPRINTER_H > + > +/* Necessary for notmuch_bool_t */ > +#include "notmuch-client.h" > + > +/* Structure printer interface. This is used to create output > + * structured as maps (with key/value pairs), lists and primitives > + * (strings, integers and booleans). > + */ > +typedef struct sprinter { > +/* Start a new map/dictionary structure. This should be followed by > + * a sequence of alternating calls to map_key and one of the > + * value-printing functions until the map is ended by end. > + */ > +void (*begin_map) (struct sprinter *); > + > +/* Start a new list/array structure. > + */ > +void (*begin_list) (struct sprinter *); > + > +/* End the last opened list or map structure. > + */ > +void (*end) (struct sprinter *); > + > +/* Print one string/integer/boolean/null element (possibly inside a > + * list or map, followed or preceded by separators). > + * For string, the char * must be UTF-8 encoded. > + */ > +void (*string) (struct sprinter *, const char *); > +void (*integer) (struct sprinter *, int); > +void (*boolean) (struct sprinter *, notmuch_bool_t); > +void (*null) (struct sprinter *); > + > +/* Print the key of a map's key/value pair. The char * must be UTF-8 > +
[PATCH v7 3/3] Use the structured formatters in notmuch-search.c.
From: This patch switches from the current ad-hoc printer to the structured formatters in sprinter.h, sprinter-text.c and sprinter-json.c. The JSON tests are changed slightly in order to make them PASS for the new structured output formatter. The text tests pass without adaptation. --- notmuch-search.c | 301 --- test/json| 34 --- 2 files changed, 103 insertions(+), 232 deletions(-) diff --git a/notmuch-search.c b/notmuch-search.c index 3be296d..07211e8 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -19,6 +19,7 @@ */ #include "notmuch-client.h" +#include "sprinter.h" typedef enum { OUTPUT_SUMMARY, @@ -28,92 +29,6 @@ typedef enum { OUTPUT_TAGS } output_t; -typedef struct search_format { -const char *results_start; -const char *item_start; -void (*item_id) (const void *ctx, -const char *item_type, -const char *item_id); -void (*thread_summary) (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); -const char *tag_start; -const char *tag; -const char *tag_sep; -const char *tag_end; -const char *item_sep; -const char *item_end; -const char *results_end; -const char *results_null; -} search_format_t; - -static void -format_item_id_text (const void *ctx, -const char *item_type, -const char *item_id); - -static void -format_thread_text (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); -static const search_format_t format_text = { -"", - "", - format_item_id_text, - format_thread_text, - " (", - "%s", " ", - ")", "\n", - "", -"\n", -"", -}; - -static void -format_item_id_json (const void *ctx, -const char *item_type, -const char *item_id); - -static void -format_thread_json (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject); - -/* Any changes to the JSON format should be reflected in the file - * devel/schemata. */ -static const search_format_t format_json = { -"[", - "{", - format_item_id_json, - format_thread_json, - "\"tags\": [", - "\"%s\"", ", ", - "]", ",\n", - "}", -"]\n", -"]\n", -}; - -static void -format_item_id_text (unused (const void *ctx), -const char *item_type, -const char *item_id) -{ -printf ("%s%s", item_type, item_id); -} - static char * sanitize_string (const void *ctx, const char *str) { @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str) return out; } -static void -format_thread_text (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("thread:%s %12s [%d/%d] %s; %s", - thread_id, - notmuch_time_relative_date (ctx, date), - matched, - total, - sanitize_string (ctx_quote, authors), - sanitize_string (ctx_quote, subject)); - -talloc_free (ctx_quote); -} - -static void -format_item_id_json (const void *ctx, -unused (const char *item_type), -const char *item_id) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("%s", json_quote_str (ctx_quote, item_id)); - -talloc_free (ctx_quote); - -} - -static void -format_thread_json (const void *ctx, - const char *thread_id, - const time_t date, - const int matched, - const int total, - const char *authors, - const char *subject) -{ -void *ctx_quote = talloc_new (ctx); - -printf ("\"thread\": %s,\n" - "\"timestamp\": %ld,\n" - "\"date_relative\": \"%s\",\n" - "\"matched\": %d,\n" - "\"total\": %d,\n" - "\"authors\": %s,\n" - "\"subject\": %s,\n", - json_quote_str (ctx_quote, thread_id), - date, - notmuch_time_relative_date (ctx, da