1 Return-Path: <craven@gmx.net>
\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 50566431FBC
\r
6 for <notmuch@notmuchmail.org>; Fri, 20 Jul 2012 01:22:38 -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 cXGgm7f4j2Sm for <notmuch@notmuchmail.org>;
\r
17 Fri, 20 Jul 2012 01:22:37 -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 676E6431FAE
\r
20 for <notmuch@notmuchmail.org>; Fri, 20 Jul 2012 01:22:36 -0700 (PDT)
\r
21 Received: (qmail invoked by alias); 20 Jul 2012 08:22:35 -0000
\r
22 Received: from gw.arelion.cust.net.lagis.at (EHLO dodekanex.arelion.at)
\r
24 by mail.gmx.net (mp030) with SMTP; 20 Jul 2012 10:22:35 +0200
\r
25 X-Authenticated: #201305
\r
26 X-Provags-ID: V01U2FsdGVkX1+yatc15kmyzlMfdtgL5I20q1emDUSI70aRua9n4V
\r
28 Received: by dodekanex.arelion.at (Postfix, from userid 1000)
\r
29 id 2C3E6301BF7; Fri, 20 Jul 2012 10:24:11 +0200 (CEST)
\r
30 From: craven@gmx.net
\r
31 To: notmuch@notmuchmail.org
\r
32 Subject: [PATCH v7 3/3] Use the structured formatters in notmuch-search.c.
\r
33 Date: Fri, 20 Jul 2012 10:23:44 +0200
\r
34 Message-Id: <1342772624-23329-1-git-send-email-craven@gmx.net>
\r
35 X-Mailer: git-send-email 1.7.11.2
\r
36 In-Reply-To: <1342766173-1344-4-git-send-email-craven@gmx.net>
\r
37 References: <1342766173-1344-4-git-send-email-craven@gmx.net>
\r
39 Content-Type: text/plain; charset=UTF-8
\r
40 Content-Transfer-Encoding: 8bit
\r
42 X-BeenThere: notmuch@notmuchmail.org
\r
43 X-Mailman-Version: 2.1.13
\r
45 List-Id: "Use and development of the notmuch mail system."
\r
46 <notmuch.notmuchmail.org>
\r
47 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
48 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
49 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
50 List-Post: <mailto:notmuch@notmuchmail.org>
\r
51 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
52 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
53 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
54 X-List-Received-Date: Fri, 20 Jul 2012 08:22:38 -0000
\r
56 From: <craven@gmx.net>
\r
58 This patch switches from the current ad-hoc printer to the structured
\r
59 formatters in sprinter.h, sprinter-text.c and sprinter-json.c.
\r
61 The JSON tests are changed slightly in order to make them PASS for the
\r
62 new structured output formatter.
\r
64 The text tests pass without adaptation.
\r
66 notmuch-search.c | 301 ++++++++++++++++---------------------------------------
\r
67 test/json | 34 ++++---
\r
68 2 files changed, 103 insertions(+), 232 deletions(-)
\r
70 diff --git a/notmuch-search.c b/notmuch-search.c
\r
71 index 3be296d..07211e8 100644
\r
72 --- a/notmuch-search.c
\r
73 +++ b/notmuch-search.c
\r
77 #include "notmuch-client.h"
\r
78 +#include "sprinter.h"
\r
82 @@ -28,92 +29,6 @@ typedef enum {
\r
86 -typedef struct search_format {
\r
87 - const char *results_start;
\r
88 - const char *item_start;
\r
89 - void (*item_id) (const void *ctx,
\r
90 - const char *item_type,
\r
91 - const char *item_id);
\r
92 - void (*thread_summary) (const void *ctx,
\r
93 - const char *thread_id,
\r
94 - const time_t date,
\r
95 - const int matched,
\r
97 - const char *authors,
\r
98 - const char *subject);
\r
99 - const char *tag_start;
\r
101 - const char *tag_sep;
\r
102 - const char *tag_end;
\r
103 - const char *item_sep;
\r
104 - const char *item_end;
\r
105 - const char *results_end;
\r
106 - const char *results_null;
\r
107 -} search_format_t;
\r
110 -format_item_id_text (const void *ctx,
\r
111 - const char *item_type,
\r
112 - const char *item_id);
\r
115 -format_thread_text (const void *ctx,
\r
116 - const char *thread_id,
\r
117 - const time_t date,
\r
118 - const int matched,
\r
120 - const char *authors,
\r
121 - const char *subject);
\r
122 -static const search_format_t format_text = {
\r
125 - format_item_id_text,
\r
126 - format_thread_text,
\r
136 -format_item_id_json (const void *ctx,
\r
137 - const char *item_type,
\r
138 - const char *item_id);
\r
141 -format_thread_json (const void *ctx,
\r
142 - const char *thread_id,
\r
143 - const time_t date,
\r
144 - const int matched,
\r
146 - const char *authors,
\r
147 - const char *subject);
\r
149 -/* Any changes to the JSON format should be reflected in the file
\r
150 - * devel/schemata. */
\r
151 -static const search_format_t format_json = {
\r
154 - format_item_id_json,
\r
155 - format_thread_json,
\r
165 -format_item_id_text (unused (const void *ctx),
\r
166 - const char *item_type,
\r
167 - const char *item_id)
\r
169 - printf ("%s%s", item_type, item_id);
\r
173 sanitize_string (const void *ctx, const char *str)
\r
175 @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
\r
180 -format_thread_text (const void *ctx,
\r
181 - const char *thread_id,
\r
182 - const time_t date,
\r
183 - const int matched,
\r
185 - const char *authors,
\r
186 - const char *subject)
\r
188 - void *ctx_quote = talloc_new (ctx);
\r
190 - printf ("thread:%s %12s [%d/%d] %s; %s",
\r
192 - notmuch_time_relative_date (ctx, date),
\r
195 - sanitize_string (ctx_quote, authors),
\r
196 - sanitize_string (ctx_quote, subject));
\r
198 - talloc_free (ctx_quote);
\r
202 -format_item_id_json (const void *ctx,
\r
203 - unused (const char *item_type),
\r
204 - const char *item_id)
\r
206 - void *ctx_quote = talloc_new (ctx);
\r
208 - printf ("%s", json_quote_str (ctx_quote, item_id));
\r
210 - talloc_free (ctx_quote);
\r
215 -format_thread_json (const void *ctx,
\r
216 - const char *thread_id,
\r
217 - const time_t date,
\r
218 - const int matched,
\r
220 - const char *authors,
\r
221 - const char *subject)
\r
223 - void *ctx_quote = talloc_new (ctx);
\r
225 - printf ("\"thread\": %s,\n"
\r
226 - "\"timestamp\": %ld,\n"
\r
227 - "\"date_relative\": \"%s\",\n"
\r
228 - "\"matched\": %d,\n"
\r
229 - "\"total\": %d,\n"
\r
230 - "\"authors\": %s,\n"
\r
231 - "\"subject\": %s,\n",
\r
232 - json_quote_str (ctx_quote, thread_id),
\r
234 - notmuch_time_relative_date (ctx, date),
\r
237 - json_quote_str (ctx_quote, authors),
\r
238 - json_quote_str (ctx_quote, subject));
\r
240 - talloc_free (ctx_quote);
\r
244 -do_search_threads (const search_format_t *format,
\r
245 +do_search_threads (sprinter_t *format,
\r
246 notmuch_query_t *query,
\r
247 notmuch_sort_t sort,
\r
249 @@ -207,7 +58,6 @@ do_search_threads (const search_format_t *format,
\r
250 notmuch_threads_t *threads;
\r
251 notmuch_tags_t *tags;
\r
253 - int first_thread = 1;
\r
257 @@ -220,14 +70,12 @@ do_search_threads (const search_format_t *format,
\r
258 if (threads == NULL)
\r
261 - fputs (format->results_start, stdout);
\r
262 + format->begin_list (format);
\r
265 notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
\r
266 notmuch_threads_move_to_next (threads), i++)
\r
268 - int first_tag = 1;
\r
270 thread = notmuch_threads_get (threads);
\r
273 @@ -235,60 +83,97 @@ do_search_threads (const search_format_t *format,
\r
277 - if (! first_thread)
\r
278 - fputs (format->item_sep, stdout);
\r
280 if (output == OUTPUT_THREADS) {
\r
281 - format->item_id (thread, "thread:",
\r
282 - notmuch_thread_get_thread_id (thread));
\r
283 + format->set_prefix (format, "thread");
\r
284 + format->string (format,
\r
285 + notmuch_thread_get_thread_id (thread));
\r
286 + format->separator (format);
\r
287 } else { /* output == OUTPUT_SUMMARY */
\r
288 - fputs (format->item_start, stdout);
\r
289 + void *ctx_quote = talloc_new (thread);
\r
290 + const char *authors = notmuch_thread_get_authors (thread);
\r
291 + const char *subject = notmuch_thread_get_subject (thread);
\r
292 + const char *thread_id = notmuch_thread_get_thread_id (thread);
\r
293 + int matched = notmuch_thread_get_matched_messages (thread);
\r
294 + int total = notmuch_thread_get_total_messages (thread);
\r
295 + const char *relative_date = NULL;
\r
296 + notmuch_bool_t first_tag = TRUE;
\r
298 + format->begin_map (format);
\r
300 if (sort == NOTMUCH_SORT_OLDEST_FIRST)
\r
301 date = notmuch_thread_get_oldest_date (thread);
\r
303 date = notmuch_thread_get_newest_date (thread);
\r
305 - format->thread_summary (thread,
\r
306 - notmuch_thread_get_thread_id (thread),
\r
308 - notmuch_thread_get_matched_messages (thread),
\r
309 - notmuch_thread_get_total_messages (thread),
\r
310 - notmuch_thread_get_authors (thread),
\r
311 - notmuch_thread_get_subject (thread));
\r
312 + relative_date = notmuch_time_relative_date (ctx_quote, date);
\r
314 + if (format->is_text_printer) {
\r
315 + /* Special case for the text formatter */
\r
316 + printf ("thread:%s %12s [%d/%d] %s; %s (",
\r
321 + sanitize_string (ctx_quote, authors),
\r
322 + sanitize_string (ctx_quote, subject));
\r
323 + } else { /* Structured Output */
\r
324 + format->map_key (format, "thread");
\r
325 + format->string (format, thread_id);
\r
326 + format->map_key (format, "timestamp");
\r
327 + format->integer (format, date);
\r
328 + format->map_key (format, "date_relative");
\r
329 + format->string (format, relative_date);
\r
330 + format->map_key (format, "matched");
\r
331 + format->integer (format, matched);
\r
332 + format->map_key (format, "total");
\r
333 + format->integer (format, total);
\r
334 + format->map_key (format, "authors");
\r
335 + format->string (format, authors);
\r
336 + format->map_key (format, "subject");
\r
337 + format->string (format, subject);
\r
340 + talloc_free (ctx_quote);
\r
342 - fputs (format->tag_start, stdout);
\r
343 + format->map_key (format, "tags");
\r
344 + format->begin_list (format);
\r
346 for (tags = notmuch_thread_get_tags (thread);
\r
347 notmuch_tags_valid (tags);
\r
348 notmuch_tags_move_to_next (tags))
\r
351 - fputs (format->tag_sep, stdout);
\r
352 - printf (format->tag, notmuch_tags_get (tags));
\r
354 + const char *tag = notmuch_tags_get (tags);
\r
356 + if (format->is_text_printer) {
\r
357 + /* Special case for the text formatter */
\r
359 + first_tag = FALSE;
\r
361 + fputc (' ', stdout);
\r
362 + fputs (tag, stdout);
\r
363 + } else { /* Structured Output */
\r
364 + format->string (format, tag);
\r
368 - fputs (format->tag_end, stdout);
\r
369 + if (format->is_text_printer)
\r
372 - fputs (format->item_end, stdout);
\r
373 + format->end (format);
\r
374 + format->end (format);
\r
375 + format->separator (format);
\r
378 - first_thread = 0;
\r
380 notmuch_thread_destroy (thread);
\r
383 - if (first_thread)
\r
384 - fputs (format->results_null, stdout);
\r
386 - fputs (format->results_end, stdout);
\r
387 + format->end (format);
\r
393 -do_search_messages (const search_format_t *format,
\r
394 +do_search_messages (sprinter_t *format,
\r
395 notmuch_query_t *query,
\r
398 @@ -297,7 +182,6 @@ do_search_messages (const search_format_t *format,
\r
399 notmuch_message_t *message;
\r
400 notmuch_messages_t *messages;
\r
401 notmuch_filenames_t *filenames;
\r
402 - int first_message = 1;
\r
406 @@ -310,7 +194,7 @@ do_search_messages (const search_format_t *format,
\r
407 if (messages == NULL)
\r
410 - fputs (format->results_start, stdout);
\r
411 + format->begin_list (format);
\r
414 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
\r
415 @@ -328,24 +212,17 @@ do_search_messages (const search_format_t *format,
\r
416 notmuch_filenames_valid (filenames);
\r
417 notmuch_filenames_move_to_next (filenames))
\r
419 - if (! first_message)
\r
420 - fputs (format->item_sep, stdout);
\r
422 - format->item_id (message, "",
\r
423 - notmuch_filenames_get (filenames));
\r
425 - first_message = 0;
\r
426 + format->string (format, notmuch_filenames_get (filenames));
\r
427 + format->separator (format);
\r
430 notmuch_filenames_destroy( filenames );
\r
432 } else { /* output == OUTPUT_MESSAGES */
\r
433 - if (! first_message)
\r
434 - fputs (format->item_sep, stdout);
\r
436 - format->item_id (message, "id:",
\r
437 - notmuch_message_get_message_id (message));
\r
438 - first_message = 0;
\r
439 + format->set_prefix (format, "id");
\r
440 + format->string (format,
\r
441 + notmuch_message_get_message_id (message));
\r
442 + format->separator (format);
\r
445 notmuch_message_destroy (message);
\r
446 @@ -353,23 +230,19 @@ do_search_messages (const search_format_t *format,
\r
448 notmuch_messages_destroy (messages);
\r
450 - if (first_message)
\r
451 - fputs (format->results_null, stdout);
\r
453 - fputs (format->results_end, stdout);
\r
454 + format->end (format);
\r
460 do_search_tags (notmuch_database_t *notmuch,
\r
461 - const search_format_t *format,
\r
462 + sprinter_t *format,
\r
463 notmuch_query_t *query)
\r
465 notmuch_messages_t *messages = NULL;
\r
466 notmuch_tags_t *tags;
\r
468 - int first_tag = 1;
\r
470 /* should the following only special case if no excluded terms
\r
472 @@ -387,7 +260,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
476 - fputs (format->results_start, stdout);
\r
477 + format->begin_list (format);
\r
480 notmuch_tags_valid (tags);
\r
481 @@ -395,12 +268,9 @@ do_search_tags (notmuch_database_t *notmuch,
\r
483 tag = notmuch_tags_get (tags);
\r
486 - fputs (format->item_sep, stdout);
\r
487 + format->string (format, tag);
\r
488 + format->separator (format);
\r
490 - format->item_id (tags, "", tag);
\r
495 notmuch_tags_destroy (tags);
\r
496 @@ -408,10 +278,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
498 notmuch_messages_destroy (messages);
\r
501 - fputs (format->results_null, stdout);
\r
503 - fputs (format->results_end, stdout);
\r
504 + format->end (format);
\r
508 @@ -430,7 +297,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
509 notmuch_query_t *query;
\r
511 notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
\r
512 - const search_format_t *format = &format_text;
\r
513 + sprinter_t *format = NULL;
\r
514 int opt_index, ret;
\r
515 output_t output = OUTPUT_SUMMARY;
\r
517 @@ -475,10 +342,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
519 switch (format_sel) {
\r
520 case NOTMUCH_FORMAT_TEXT:
\r
521 - format = &format_text;
\r
522 + format = sprinter_text_create (ctx, stdout);
\r
524 case NOTMUCH_FORMAT_JSON:
\r
525 - format = &format_json;
\r
526 + format = sprinter_json_create (ctx, stdout);
\r
530 @@ -546,5 +413,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
531 notmuch_query_destroy (query);
\r
532 notmuch_database_destroy (notmuch);
\r
534 + talloc_free (format);
\r
538 diff --git a/test/json b/test/json
\r
539 index 6439788..337b3f5 100755
\r
542 @@ -9,15 +9,16 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e
\r
544 test_begin_subtest "Search message: json"
\r
545 add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
\r
546 -output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
\r
547 +output=$(notmuch search --format=json "json-search-message" | notmuch_json_show_sanitize | notmuch_search_sanitize)
\r
548 test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
549 -\"timestamp\": 946728000,
\r
550 -\"date_relative\": \"2000-01-01\",
\r
553 -\"authors\": \"Notmuch Test Suite\",
\r
554 -\"subject\": \"json-search-subject\",
\r
555 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
556 + \"timestamp\": 946728000,
\r
557 + \"date_relative\": \"2000-01-01\",
\r
560 + \"authors\": \"Notmuch Test Suite\",
\r
561 + \"subject\": \"json-search-subject\",
\r
562 + \"tags\": [\"inbox\",
\r
565 test_begin_subtest "Show message: json, utf-8"
\r
566 add_message "[subject]=\"json-show-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-show-méssage\""
\r
567 @@ -39,14 +40,15 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":
\r
569 test_begin_subtest "Search message: json, utf-8"
\r
570 add_message "[subject]=\"json-search-utf8-body-sübjéct\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"jsön-search-méssage\""
\r
571 -output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
\r
572 +output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_json_show_sanitize | notmuch_search_sanitize)
\r
573 test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
574 -\"timestamp\": 946728000,
\r
575 -\"date_relative\": \"2000-01-01\",
\r
578 -\"authors\": \"Notmuch Test Suite\",
\r
579 -\"subject\": \"json-search-utf8-body-sübjéct\",
\r
580 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
581 + \"timestamp\": 946728000,
\r
582 + \"date_relative\": \"2000-01-01\",
\r
585 + \"authors\": \"Notmuch Test Suite\",
\r
586 + \"subject\": \"json-search-utf8-body-sübjéct\",
\r
587 + \"tags\": [\"inbox\",
\r