1 Return-Path: <peter.feigl@gmx.at>
\r
2 X-Original-To: notmuch@notmuchmail.org
\r
3 Delivered-To: notmuch@notmuchmail.org
\r
4 Received: from localhost (localhost [127.0.0.1])
\r
5 by olra.theworths.org (Postfix) with ESMTP id AF97A431E64
\r
6 for <notmuch@notmuchmail.org>; Tue, 10 Jul 2012 03:02:19 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=0.001 tagged_above=-999 required=5
\r
12 tests=[FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001]
\r
14 Received: from olra.theworths.org ([127.0.0.1])
\r
15 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
16 with ESMTP id Ub-HEPOmCRou for <notmuch@notmuchmail.org>;
\r
17 Tue, 10 Jul 2012 03:02:18 -0700 (PDT)
\r
18 Received: from mailout-de.gmx.net (mailout-de.gmx.net [213.165.64.22])
\r
19 by olra.theworths.org (Postfix) with SMTP id B05BF431FBF
\r
20 for <notmuch@notmuchmail.org>; Tue, 10 Jul 2012 03:02:17 -0700 (PDT)
\r
21 Received: (qmail invoked by alias); 10 Jul 2012 10:02:13 -0000
\r
22 Received: from www.nexoid.at (EHLO mail.nexoid.at) [178.79.130.240]
\r
23 by mail.gmx.net (mp002) with SMTP; 10 Jul 2012 12:02:13 +0200
\r
24 X-Authenticated: #4563876
\r
25 X-Provags-ID: V01U2FsdGVkX18E2BQDiKkEnJg8tM91d5IrET33+6Ioc1l4eR2GfP
\r
27 Received: from nexoid (localhost [127.0.0.1])
\r
28 by mail.nexoid.at (Postfix) with ESMTP id 91B18EDDE
\r
29 for <notmuch@notmuchmail.org>; Tue, 10 Jul 2012 12:02:11 +0200 (CEST)
\r
30 From: <craven@gmx.net>
\r
31 To: notmuch@notmuchmail.org
\r
32 Subject: [PATCH] Added better support for multiple structured output formats.
\r
33 User-Agent: Notmuch/0.11+77~gad6d0d5 (http://notmuchmail.org) Emacs/24.1.50.2
\r
35 Date: Tue, 10 Jul 2012 12:02:11 +0200
\r
36 Message-ID: <87liisue70.fsf@nexoid.at>
\r
38 Content-Type: text/plain
\r
40 X-BeenThere: notmuch@notmuchmail.org
\r
41 X-Mailman-Version: 2.1.13
\r
43 List-Id: "Use and development of the notmuch mail system."
\r
44 <notmuch.notmuchmail.org>
\r
45 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
46 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
47 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
48 List-Post: <mailto:notmuch@notmuchmail.org>
\r
49 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
50 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
51 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
52 X-List-Received-Date: Tue, 10 Jul 2012 10:02:19 -0000
\r
54 As discussed in <id:20120121220407.GK16740@mit.edu>, this patch adds
\r
55 support for new structured output formats (like s-expressions) by using
\r
56 stateful structure_printers. An implementation of the JSON structure
\r
57 printer that passes all tests is included.
\r
59 Structure printers have functions for starting a map, a list, closing
\r
60 any number of these two, printing a map key, a number value, a string
\r
61 value, and boolean values. By threading a state through the
\r
62 invocations, arbitrary structured formatting can be achieved.
\r
64 In a second patch, the structured output code should be isolated in a
\r
65 separate file, and also used in all other parts of notmuch.
\r
67 notmuch-search.c | 458 ++++++++++++++++++++++++++++++++++++++-----------------
\r
68 1 file changed, 322 insertions(+), 136 deletions(-)
\r
70 diff --git a/notmuch-search.c b/notmuch-search.c
\r
71 index fa5086e..3413b79 100644
\r
72 --- a/notmuch-search.c
\r
73 +++ b/notmuch-search.c
\r
74 @@ -28,19 +28,181 @@ typedef enum {
\r
78 +typedef void * structure_printer_state_t;
\r
80 typedef struct structure_printer {
\r
81 - int (*map)(struct structure_printer_t *sp);
\r
82 - int (*list)(struct structure_printer_t *sp);
\r
83 - void (*pop)(struct structure_printer_t *sp, int level);
\r
84 - void (*map_key)(struct structure_printer_t *sp, const char *key);
\r
85 - void (*number)(struct structure_printer_t *sp, int val);
\r
86 - void (*string)(struct structure_printer_t *sp, const char *val);
\r
87 - void (*bool)(struct structure_printer_t *sp, notmuch_bool_t val);
\r
88 - void *(*initial_context)(struct structure_printer_t *sp);
\r
89 + int (*map)(void *state);
\r
90 + int (*list)(void *state);
\r
91 + void (*pop)(void *state, int level);
\r
92 + void (*map_key)(void *state, const char *key);
\r
93 + void (*number)(void *state, int val);
\r
94 + void (*string)(void *state, const char *val);
\r
95 + void (*bool)(void *state, notmuch_bool_t val);
\r
96 + void *(*initial_state)(const struct structure_printer *sp, FILE *output);
\r
97 } structure_printer_t;
\r
99 -struct structure_printer_t *new_search_format_structure_printer(FILE *stream, struct search_format_t *search_format);
\r
100 +/* JSON structure printer */
\r
102 +typedef struct json_list {
\r
104 + int first_already_seen;
\r
105 + struct json_list *rest;
\r
108 +#define TYPE_JSON_MAP 1
\r
109 +#define TYPE_JSON_ARRAY 2
\r
111 +typedef struct json_state {
\r
113 + json_list_t *stack;
\r
117 +int json_map(void *state);
\r
118 +int json_list(void *state);
\r
119 +void json_pop(void *state, int level);
\r
120 +void json_map_key(void *state, const char *key);
\r
121 +void json_number(void *state, int val);
\r
122 +void json_string(void *state, const char *val);
\r
123 +void json_bool(void *state, notmuch_bool_t val);
\r
124 +void *json_initial_state(const struct structure_printer *sp, FILE *output);
\r
126 +int json_map(void *st) {
\r
127 + json_state_t *state = (json_state_t*)st;
\r
128 + FILE *output = state->output;
\r
129 + if(state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) {
\r
130 + fputs(",", output);
\r
131 + if(state->level == 1)
\r
132 + fputs("\n", output);
\r
134 + fputs(" ", output);
\r
136 + if(state->stack != NULL) {
\r
137 + state->stack->first_already_seen = TRUE;
\r
139 + fputs("{", output);
\r
140 + void *ctx_json_map = talloc_new (0);
\r
141 + json_list_t *el = talloc(ctx_json_map, json_list_t);
\r
142 + el->type = TYPE_JSON_MAP;
\r
143 + el->first_already_seen = FALSE;
\r
144 + el->rest = state->stack;
\r
145 + state->stack = el;
\r
146 + return state->level++;
\r
149 +int json_list(void *st) {
\r
150 + json_state_t *state = (json_state_t*)st;
\r
151 + FILE *output = state->output;
\r
152 + if(state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) {
\r
153 + fputs(",", output);
\r
154 + if(state->level == 1)
\r
155 + fputs("\n", output);
\r
157 + fputs(" ", output);
\r
159 + if(state->stack != NULL) {
\r
160 + state->stack->first_already_seen = TRUE;
\r
162 + fputs("[", output);
\r
163 + void *ctx_json_map = talloc_new (0);
\r
164 + json_list_t *el = talloc(ctx_json_map, json_list_t);
\r
165 + el->type = TYPE_JSON_ARRAY;
\r
166 + el->first_already_seen = FALSE;
\r
167 + el->rest = state->stack;
\r
168 + state->stack = el;
\r
169 + return state->level++;
\r
172 +void json_pop(void *st, int level) {
\r
174 + json_state_t *state = (json_state_t*)st;
\r
175 + FILE *output = state->output;
\r
176 + for(i = state->level; i > level; i--) {
\r
177 + json_list_t *tos = state->stack;
\r
178 + if(tos->type == TYPE_JSON_MAP) {
\r
179 + fputs("}", output);
\r
181 + if(tos->type == TYPE_JSON_ARRAY) {
\r
182 + fputs("]", output);
\r
184 + state->stack = tos->rest;
\r
186 + talloc_free(tos);
\r
188 + if(state->level == 0)
\r
189 + fputs("\n", output);
\r
192 +void json_map_key(void *st, const char *key) {
\r
193 + json_state_t *state = (json_state_t*)st;
\r
194 + FILE *output = state->output;
\r
195 + if(state->stack != NULL && state->stack->first_already_seen) {
\r
196 + fputs(",\n", output);
\r
198 + fputs("\"", output);
\r
199 + fputs(key, output);
\r
200 + fputs("\": ", output);
\r
203 +void json_number(void *st, int val) {
\r
204 + json_state_t *state = (json_state_t*)st;
\r
205 + FILE *output = state->output;
\r
206 + if(state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) {
\r
207 + fputs(", ", output);
\r
209 + state->stack->first_already_seen = TRUE;
\r
210 + fprintf(output, "%i", val);
\r
213 +void json_string(void *st, const char *val) {
\r
214 + json_state_t *state = (json_state_t*)st;
\r
215 + FILE *output = state->output;
\r
216 + void *ctx = talloc_new(0);
\r
217 + if(state->stack != NULL && state->stack->type == TYPE_JSON_ARRAY && state->stack->first_already_seen) {
\r
218 + fputs(",", output);
\r
219 + if(state->level == 1)
\r
220 + fputs("\n", output);
\r
222 + fputs(" ", output);
\r
225 + state->stack->first_already_seen = TRUE;
\r
226 + fprintf(output, "%s", json_quote_str(ctx, val));
\r
227 + talloc_free(ctx);
\r
230 +void json_bool(void *st, notmuch_bool_t val) {
\r
231 + json_state_t *state = (json_state_t*)st;
\r
232 + FILE *output = state->output;
\r
234 + fputs("true", output);
\r
236 + fputs("false", output);
\r
239 +void *json_initial_state(const struct structure_printer *sp, FILE *output) {
\r
241 + json_state_t *st = talloc(0, json_state_t);
\r
243 + st->stack = NULL;
\r
244 + st->output = output;
\r
248 +structure_printer_t json_structure_printer = {
\r
256 + &json_initial_state
\r
259 +structure_printer_t *text_structure_printer = NULL;
\r
261 +/* legacy, only needed for non-structured text output */
\r
262 typedef struct search_format {
\r
263 const char *results_start;
\r
264 const char *item_start;
\r
265 @@ -64,6 +226,7 @@ typedef struct search_format {
\r
266 const char *results_null;
\r
271 format_item_id_text (const void *ctx,
\r
272 const char *item_type,
\r
273 @@ -77,6 +240,7 @@ format_thread_text (const void *ctx,
\r
275 const char *authors,
\r
276 const char *subject);
\r
278 static const search_format_t format_text = {
\r
281 @@ -91,35 +255,6 @@ static const search_format_t format_text = {
\r
285 -format_item_id_json (const void *ctx,
\r
286 - const char *item_type,
\r
287 - const char *item_id);
\r
290 -format_thread_json (const void *ctx,
\r
291 - const char *thread_id,
\r
292 - const time_t date,
\r
293 - const int matched,
\r
295 - const char *authors,
\r
296 - const char *subject);
\r
298 -/* Any changes to the JSON format should be reflected in the file
\r
299 - * devel/schemata. */
\r
300 -static const search_format_t format_json = {
\r
303 - format_item_id_json,
\r
304 - format_thread_json,
\r
314 format_item_id_text (unused (const void *ctx),
\r
315 const char *item_type,
\r
316 const char *item_id)
\r
317 @@ -166,50 +301,9 @@ format_thread_text (const void *ctx,
\r
318 talloc_free (ctx_quote);
\r
322 -format_item_id_json (const void *ctx,
\r
323 - unused (const char *item_type),
\r
324 - const char *item_id)
\r
326 - void *ctx_quote = talloc_new (ctx);
\r
328 - printf ("%s", json_quote_str (ctx_quote, item_id));
\r
330 - talloc_free (ctx_quote);
\r
335 -format_thread_json (const void *ctx,
\r
336 - const char *thread_id,
\r
337 - const time_t date,
\r
338 - const int matched,
\r
340 - const char *authors,
\r
341 - const char *subject)
\r
343 - void *ctx_quote = talloc_new (ctx);
\r
345 - printf ("\"thread\": %s,\n"
\r
346 - "\"timestamp\": %ld,\n"
\r
347 - "\"date_relative\": \"%s\",\n"
\r
348 - "\"matched\": %d,\n"
\r
349 - "\"total\": %d,\n"
\r
350 - "\"authors\": %s,\n"
\r
351 - "\"subject\": %s,\n",
\r
352 - json_quote_str (ctx_quote, thread_id),
\r
354 - notmuch_time_relative_date (ctx, date),
\r
357 - json_quote_str (ctx_quote, authors),
\r
358 - json_quote_str (ctx_quote, subject));
\r
360 - talloc_free (ctx_quote);
\r
364 -do_search_threads (const search_format_t *format,
\r
365 +do_search_threads (const structure_printer_t *format,
\r
367 notmuch_query_t *query,
\r
368 notmuch_sort_t sort,
\r
370 @@ -222,7 +316,8 @@ do_search_threads (const search_format_t *format,
\r
372 int first_thread = 1;
\r
375 + int outermost_level = 0;
\r
376 + int items_level = 0;
\r
378 offset += notmuch_query_count_threads (query);
\r
380 @@ -233,7 +328,10 @@ do_search_threads (const search_format_t *format,
\r
381 if (threads == NULL)
\r
384 - fputs (format->results_start, stdout);
\r
385 + if(format == text_structure_printer)
\r
386 + fputs(format_text.results_start, stdout);
\r
388 + outermost_level = format->list(state);
\r
391 notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
\r
392 @@ -248,43 +346,93 @@ do_search_threads (const search_format_t *format,
\r
396 - if (! first_thread)
\r
397 - fputs (format->item_sep, stdout);
\r
398 + if (format == text_structure_printer && ! first_thread)
\r
399 + fputs (format_text.item_sep, stdout);
\r
401 if (output == OUTPUT_THREADS) {
\r
402 - format->item_id (thread, "thread:",
\r
403 - notmuch_thread_get_thread_id (thread));
\r
404 + if(format == text_structure_printer) {
\r
405 + format_text.item_id (thread, "thread:",
\r
406 + notmuch_thread_get_thread_id (thread));
\r
409 + char buffer[128];
\r
410 + strncpy(buffer, "thread:", 1 + strlen("thread:"));
\r
411 + strncat(buffer, notmuch_thread_get_thread_id (thread), 128 - strlen("thread:"));
\r
412 + format->string(state, buffer);
\r
415 } else { /* output == OUTPUT_SUMMARY */
\r
416 - fputs (format->item_start, stdout);
\r
417 + int tags_level = 0;
\r
418 + void *ctx = talloc_new (0);
\r
420 + if(format == text_structure_printer)
\r
421 + fputs (format_text.item_start, stdout);
\r
423 + items_level = format->map(state);
\r
425 if (sort == NOTMUCH_SORT_OLDEST_FIRST)
\r
426 date = notmuch_thread_get_oldest_date (thread);
\r
428 date = notmuch_thread_get_newest_date (thread);
\r
430 - format->thread_summary (thread,
\r
431 - notmuch_thread_get_thread_id (thread),
\r
433 - notmuch_thread_get_matched_messages (thread),
\r
434 - notmuch_thread_get_total_messages (thread),
\r
435 - notmuch_thread_get_authors (thread),
\r
436 - notmuch_thread_get_subject (thread));
\r
437 + if(format == text_structure_printer) {
\r
438 + format_text.thread_summary (thread,
\r
439 + notmuch_thread_get_thread_id (thread),
\r
441 + notmuch_thread_get_matched_messages (thread),
\r
442 + notmuch_thread_get_total_messages (thread),
\r
443 + notmuch_thread_get_authors (thread),
\r
444 + notmuch_thread_get_subject (thread));
\r
446 + format->map_key(state, "thread");
\r
447 + format->string(state, notmuch_thread_get_thread_id (thread));
\r
448 + format->map_key(state, "timestamp");
\r
449 + format->number(state, date);
\r
450 + format->map_key(state, "date_relative");
\r
451 + format->string(state, notmuch_time_relative_date(ctx, date));
\r
452 + format->map_key(state, "matched");
\r
453 + format->number(state, notmuch_thread_get_matched_messages(thread));
\r
454 + format->map_key(state, "total");
\r
455 + format->number(state, notmuch_thread_get_total_messages(thread));
\r
456 + format->map_key(state, "authors");
\r
457 + format->string(state, notmuch_thread_get_authors(thread));
\r
458 + format->map_key(state, "subject");
\r
459 + format->string(state, notmuch_thread_get_subject(thread));
\r
462 + if(format == text_structure_printer) {
\r
463 + fputs (format_text.tag_start, stdout);
\r
465 + format->map_key(state, "tags");
\r
467 + tags_level = format->list(state);
\r
470 - fputs (format->tag_start, stdout);
\r
472 for (tags = notmuch_thread_get_tags (thread);
\r
473 notmuch_tags_valid (tags);
\r
474 notmuch_tags_move_to_next (tags))
\r
477 - fputs (format->tag_sep, stdout);
\r
478 - printf (format->tag, notmuch_tags_get (tags));
\r
479 + if (format == text_structure_printer && ! first_tag) {
\r
480 + fputs (format_text.tag_sep, stdout);
\r
482 + if(format == text_structure_printer) {
\r
483 + printf (format_text.tag, notmuch_tags_get (tags));
\r
485 + format->string(state, notmuch_tags_get(tags));
\r
490 - fputs (format->tag_end, stdout);
\r
491 + if(format == text_structure_printer)
\r
492 + fputs (format_text.tag_end, stdout);
\r
494 + format->pop(state, tags_level);
\r
496 - fputs (format->item_end, stdout);
\r
497 + if(format == text_structure_printer)
\r
498 + fputs (format_text.item_end, stdout);
\r
500 + format->pop(state, items_level);
\r
504 @@ -292,16 +440,21 @@ do_search_threads (const search_format_t *format,
\r
505 notmuch_thread_destroy (thread);
\r
508 - if (first_thread)
\r
509 - fputs (format->results_null, stdout);
\r
511 - fputs (format->results_end, stdout);
\r
512 + if(format == text_structure_printer) {
\r
513 + if (first_thread)
\r
514 + fputs (format_text.results_null, stdout);
\r
516 + fputs (format_text.results_end, stdout);
\r
518 + format->pop(state, outermost_level);
\r
525 -do_search_messages (const search_format_t *format,
\r
526 +do_search_messages (const structure_printer_t *format,
\r
528 notmuch_query_t *query,
\r
531 @@ -312,6 +465,7 @@ do_search_messages (const search_format_t *format,
\r
532 notmuch_filenames_t *filenames;
\r
533 int first_message = 1;
\r
535 + int outermost_level = 0;
\r
538 offset += notmuch_query_count_messages (query);
\r
539 @@ -323,7 +477,10 @@ do_search_messages (const search_format_t *format,
\r
540 if (messages == NULL)
\r
543 - fputs (format->results_start, stdout);
\r
544 + if(format == text_structure_printer)
\r
545 + fputs (format_text.results_start, stdout);
\r
547 + outermost_level = format->list(state);
\r
550 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
\r
551 @@ -341,23 +498,32 @@ do_search_messages (const search_format_t *format,
\r
552 notmuch_filenames_valid (filenames);
\r
553 notmuch_filenames_move_to_next (filenames))
\r
555 - if (! first_message)
\r
556 - fputs (format->item_sep, stdout);
\r
558 - format->item_id (message, "",
\r
559 - notmuch_filenames_get (filenames));
\r
561 + if(format == text_structure_printer) {
\r
562 + if (! first_message)
\r
563 + fputs (format_text.item_sep, stdout);
\r
565 + format_text.item_id (message, "",
\r
566 + notmuch_filenames_get (filenames));
\r
568 + format->string(state, notmuch_filenames_get (filenames));
\r
574 notmuch_filenames_destroy( filenames );
\r
576 } else { /* output == OUTPUT_MESSAGES */
\r
577 - if (! first_message)
\r
578 - fputs (format->item_sep, stdout);
\r
579 + if(format == text_structure_printer) {
\r
580 + if (! first_message)
\r
581 + fputs (format_text.item_sep, stdout);
\r
583 + format_text.item_id (message, "id:",
\r
584 + notmuch_message_get_message_id (message));
\r
586 + format->string(state, notmuch_message_get_message_id (message));
\r
589 - format->item_id (message, "id:",
\r
590 - notmuch_message_get_message_id (message));
\r
594 @@ -366,23 +532,29 @@ do_search_messages (const search_format_t *format,
\r
596 notmuch_messages_destroy (messages);
\r
598 - if (first_message)
\r
599 - fputs (format->results_null, stdout);
\r
601 - fputs (format->results_end, stdout);
\r
602 + if(format == text_structure_printer) {
\r
603 + if (first_message)
\r
604 + fputs (format_text.results_null, stdout);
\r
606 + fputs (format_text.results_end, stdout);
\r
608 + format->pop(state, outermost_level);
\r
615 do_search_tags (notmuch_database_t *notmuch,
\r
616 - const search_format_t *format,
\r
617 + const structure_printer_t *format,
\r
619 notmuch_query_t *query)
\r
621 notmuch_messages_t *messages = NULL;
\r
622 notmuch_tags_t *tags;
\r
625 + int outermost_level = 0;
\r
627 /* should the following only special case if no excluded terms
\r
629 @@ -400,7 +572,10 @@ do_search_tags (notmuch_database_t *notmuch,
\r
633 - fputs (format->results_start, stdout);
\r
634 + if(format == text_structure_printer)
\r
635 + fputs (format_text.results_start, stdout);
\r
637 + outermost_level = format->list(state);
\r
640 notmuch_tags_valid (tags);
\r
641 @@ -408,10 +583,14 @@ do_search_tags (notmuch_database_t *notmuch,
\r
643 tag = notmuch_tags_get (tags);
\r
646 - fputs (format->item_sep, stdout);
\r
647 + if(format == text_structure_printer) {
\r
649 + fputs (format_text.item_sep, stdout);
\r
651 - format->item_id (tags, "", tag);
\r
652 + format_text.item_id (tags, "", tag);
\r
654 + format->string(state, tag);
\r
659 @@ -421,10 +600,14 @@ do_search_tags (notmuch_database_t *notmuch,
\r
661 notmuch_messages_destroy (messages);
\r
664 - fputs (format->results_null, stdout);
\r
666 - fputs (format->results_end, stdout);
\r
667 + if(format == text_structure_printer) {
\r
669 + fputs (format_text.results_null, stdout);
\r
671 + fputs (format_text.results_end, stdout);
\r
673 + format->pop(state, outermost_level);
\r
678 @@ -443,7 +626,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
679 notmuch_query_t *query;
\r
681 notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
\r
682 - const search_format_t *format = &format_text;
\r
683 + const structure_printer_t *format = text_structure_printer;
\r
684 + void *state = NULL;
\r
685 int opt_index, ret;
\r
686 output_t output = OUTPUT_SUMMARY;
\r
688 @@ -488,10 +672,12 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
690 switch (format_sel) {
\r
691 case NOTMUCH_FORMAT_TEXT:
\r
692 - format = &format_text;
\r
693 + format = text_structure_printer;
\r
696 case NOTMUCH_FORMAT_JSON:
\r
697 - format = &format_json;
\r
698 + format = &json_structure_printer;
\r
699 + state = format->initial_state(format, stdout);
\r
703 @@ -545,14 +731,14 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
705 case OUTPUT_SUMMARY:
\r
706 case OUTPUT_THREADS:
\r
707 - ret = do_search_threads (format, query, sort, output, offset, limit);
\r
708 + ret = do_search_threads (format, state, query, sort, output, offset, limit);
\r
710 case OUTPUT_MESSAGES:
\r
712 - ret = do_search_messages (format, query, output, offset, limit);
\r
713 + ret = do_search_messages (format, state, query, output, offset, limit);
\r
716 - ret = do_search_tags (notmuch, format, query);
\r
717 + ret = do_search_tags (notmuch, format, state, query);
\r