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 615DC431FC2
\r
6 for <notmuch@notmuchmail.org>; Thu, 19 Jul 2012 23:34:53 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=1.106 tagged_above=-999 required=5
\r
12 tests=[FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001,
\r
13 SUBJ_ILLEGAL_CHARS=1.105] autolearn=disabled
\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 odpHGXW2CWrm for <notmuch@notmuchmail.org>;
\r
17 Thu, 19 Jul 2012 23:34:48 -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 2D281431FAE
\r
20 for <notmuch@notmuchmail.org>; Thu, 19 Jul 2012 23:34:47 -0700 (PDT)
\r
21 Received: (qmail invoked by alias); 20 Jul 2012 06:34:45 -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 08:34:45 +0200
\r
25 X-Authenticated: #201305
\r
26 X-Provags-ID: V01U2FsdGVkX1/jQLEXaAPjZI63WYGXbxNYAE74E5tRv7c34OeX6Y
\r
28 Received: by dodekanex.arelion.at (Postfix, from userid 1000)
\r
29 id 1CE61301BF9; Fri, 20 Jul 2012 08:36:18 +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 08:36:13 +0200
\r
34 Message-Id: <1342766173-1344-4-git-send-email-craven@gmx.net>
\r
35 X-Mailer: git-send-email 1.7.11.2
\r
36 In-Reply-To: <1342766173-1344-1-git-send-email-craven@gmx.net>
\r
37 References: <20120718194819.GP31670@mit.edu>
\r
38 <1342766173-1344-1-git-send-email-craven@gmx.net>
\r
40 Content-Type: text/plain; charset=
\10\10\r
41 Content-Transfer-Encoding: 8bit
\r
43 X-BeenThere: notmuch@notmuchmail.org
\r
44 X-Mailman-Version: 2.1.13
\r
46 List-Id: "Use and development of the notmuch mail system."
\r
47 <notmuch.notmuchmail.org>
\r
48 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
49 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
50 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
51 List-Post: <mailto:notmuch@notmuchmail.org>
\r
52 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
53 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
54 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
55 X-List-Received-Date: Fri, 20 Jul 2012 06:34:55 -0000
\r
57 From: <craven@gmx.net>
\r
59 This patch switches from the current ad-hoc printer to the structured
\r
60 formatters in sprinter.h, sprinter-text.c and sprinter-json.c.
\r
62 The JSON tests are changed slightly in order to make them PASS for the
\r
63 new structured output formatter.
\r
65 The text tests pass without adaptation.
\r
67 notmuch-search.c | 301 ++++++++++++++++---------------------------------------
\r
68 test/json | 34 ++++---
\r
69 2 files changed, 103 insertions(+), 232 deletions(-)
\r
71 diff --git a/notmuch-search.c b/notmuch-search.c
\r
72 index 3be296d..07211e8 100644
\r
73 --- a/notmuch-search.c
\r
74 +++ b/notmuch-search.c
\r
78 #include "notmuch-client.h"
\r
79 +#include "sprinter.h"
\r
83 @@ -28,92 +29,6 @@ typedef enum {
\r
87 -typedef struct search_format {
\r
88 - const char *results_start;
\r
89 - const char *item_start;
\r
90 - void (*item_id) (const void *ctx,
\r
91 - const char *item_type,
\r
92 - const char *item_id);
\r
93 - void (*thread_summary) (const void *ctx,
\r
94 - const char *thread_id,
\r
95 - const time_t date,
\r
96 - const int matched,
\r
98 - const char *authors,
\r
99 - const char *subject);
\r
100 - const char *tag_start;
\r
102 - const char *tag_sep;
\r
103 - const char *tag_end;
\r
104 - const char *item_sep;
\r
105 - const char *item_end;
\r
106 - const char *results_end;
\r
107 - const char *results_null;
\r
108 -} search_format_t;
\r
111 -format_item_id_text (const void *ctx,
\r
112 - const char *item_type,
\r
113 - const char *item_id);
\r
116 -format_thread_text (const void *ctx,
\r
117 - const char *thread_id,
\r
118 - const time_t date,
\r
119 - const int matched,
\r
121 - const char *authors,
\r
122 - const char *subject);
\r
123 -static const search_format_t format_text = {
\r
126 - format_item_id_text,
\r
127 - format_thread_text,
\r
137 -format_item_id_json (const void *ctx,
\r
138 - const char *item_type,
\r
139 - const char *item_id);
\r
142 -format_thread_json (const void *ctx,
\r
143 - const char *thread_id,
\r
144 - const time_t date,
\r
145 - const int matched,
\r
147 - const char *authors,
\r
148 - const char *subject);
\r
150 -/* Any changes to the JSON format should be reflected in the file
\r
151 - * devel/schemata. */
\r
152 -static const search_format_t format_json = {
\r
155 - format_item_id_json,
\r
156 - format_thread_json,
\r
166 -format_item_id_text (unused (const void *ctx),
\r
167 - const char *item_type,
\r
168 - const char *item_id)
\r
170 - printf ("%s%s", item_type, item_id);
\r
174 sanitize_string (const void *ctx, const char *str)
\r
176 @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
\r
181 -format_thread_text (const void *ctx,
\r
182 - const char *thread_id,
\r
183 - const time_t date,
\r
184 - const int matched,
\r
186 - const char *authors,
\r
187 - const char *subject)
\r
189 - void *ctx_quote = talloc_new (ctx);
\r
191 - printf ("thread:%s %12s [%d/%d] %s; %s",
\r
193 - notmuch_time_relative_date (ctx, date),
\r
196 - sanitize_string (ctx_quote, authors),
\r
197 - sanitize_string (ctx_quote, subject));
\r
199 - talloc_free (ctx_quote);
\r
203 -format_item_id_json (const void *ctx,
\r
204 - unused (const char *item_type),
\r
205 - const char *item_id)
\r
207 - void *ctx_quote = talloc_new (ctx);
\r
209 - printf ("%s", json_quote_str (ctx_quote, item_id));
\r
211 - talloc_free (ctx_quote);
\r
216 -format_thread_json (const void *ctx,
\r
217 - const char *thread_id,
\r
218 - const time_t date,
\r
219 - const int matched,
\r
221 - const char *authors,
\r
222 - const char *subject)
\r
224 - void *ctx_quote = talloc_new (ctx);
\r
226 - printf ("\"thread\": %s,\n"
\r
227 - "\"timestamp\": %ld,\n"
\r
228 - "\"date_relative\": \"%s\",\n"
\r
229 - "\"matched\": %d,\n"
\r
230 - "\"total\": %d,\n"
\r
231 - "\"authors\": %s,\n"
\r
232 - "\"subject\": %s,\n",
\r
233 - json_quote_str (ctx_quote, thread_id),
\r
235 - notmuch_time_relative_date (ctx, date),
\r
238 - json_quote_str (ctx_quote, authors),
\r
239 - json_quote_str (ctx_quote, subject));
\r
241 - talloc_free (ctx_quote);
\r
245 -do_search_threads (const search_format_t *format,
\r
246 +do_search_threads (sprinter_t *format,
\r
247 notmuch_query_t *query,
\r
248 notmuch_sort_t sort,
\r
250 @@ -207,7 +58,6 @@ do_search_threads (const search_format_t *format,
\r
251 notmuch_threads_t *threads;
\r
252 notmuch_tags_t *tags;
\r
254 - int first_thread = 1;
\r
258 @@ -220,14 +70,12 @@ do_search_threads (const search_format_t *format,
\r
259 if (threads == NULL)
\r
262 - fputs (format->results_start, stdout);
\r
263 + format->begin_list (format);
\r
266 notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
\r
267 notmuch_threads_move_to_next (threads), i++)
\r
269 - int first_tag = 1;
\r
271 thread = notmuch_threads_get (threads);
\r
274 @@ -235,60 +83,97 @@ do_search_threads (const search_format_t *format,
\r
278 - if (! first_thread)
\r
279 - fputs (format->item_sep, stdout);
\r
281 if (output == OUTPUT_THREADS) {
\r
282 - format->item_id (thread, "thread:",
\r
283 - notmuch_thread_get_thread_id (thread));
\r
284 + format->set_prefix (format, "thread");
\r
285 + format->string (format,
\r
286 + notmuch_thread_get_thread_id (thread));
\r
287 + format->separator (format);
\r
288 } else { /* output == OUTPUT_SUMMARY */
\r
289 - fputs (format->item_start, stdout);
\r
290 + void *ctx_quote = talloc_new (thread);
\r
291 + const char *authors = notmuch_thread_get_authors (thread);
\r
292 + const char *subject = notmuch_thread_get_subject (thread);
\r
293 + const char *thread_id = notmuch_thread_get_thread_id (thread);
\r
294 + int matched = notmuch_thread_get_matched_messages (thread);
\r
295 + int total = notmuch_thread_get_total_messages (thread);
\r
296 + const char *relative_date = NULL;
\r
297 + notmuch_bool_t first_tag = TRUE;
\r
299 + format->begin_map (format);
\r
301 if (sort == NOTMUCH_SORT_OLDEST_FIRST)
\r
302 date = notmuch_thread_get_oldest_date (thread);
\r
304 date = notmuch_thread_get_newest_date (thread);
\r
306 - format->thread_summary (thread,
\r
307 - notmuch_thread_get_thread_id (thread),
\r
309 - notmuch_thread_get_matched_messages (thread),
\r
310 - notmuch_thread_get_total_messages (thread),
\r
311 - notmuch_thread_get_authors (thread),
\r
312 - notmuch_thread_get_subject (thread));
\r
313 + relative_date = notmuch_time_relative_date (ctx_quote, date);
\r
315 + if (format->is_text_printer) {
\r
316 + /* Special case for the text formatter */
\r
317 + printf ("thread:%s %12s [%d/%d] %s; %s (",
\r
322 + sanitize_string (ctx_quote, authors),
\r
323 + sanitize_string (ctx_quote, subject));
\r
324 + } else { /* Structured Output */
\r
325 + format->map_key (format, "thread");
\r
326 + format->string (format, thread_id);
\r
327 + format->map_key (format, "timestamp");
\r
328 + format->integer (format, date);
\r
329 + format->map_key (format, "date_relative");
\r
330 + format->string (format, relative_date);
\r
331 + format->map_key (format, "matched");
\r
332 + format->integer (format, matched);
\r
333 + format->map_key (format, "total");
\r
334 + format->integer (format, total);
\r
335 + format->map_key (format, "authors");
\r
336 + format->string (format, authors);
\r
337 + format->map_key (format, "subject");
\r
338 + format->string (format, subject);
\r
341 + talloc_free (ctx_quote);
\r
343 - fputs (format->tag_start, stdout);
\r
344 + format->map_key (format, "tags");
\r
345 + format->begin_list (format);
\r
347 for (tags = notmuch_thread_get_tags (thread);
\r
348 notmuch_tags_valid (tags);
\r
349 notmuch_tags_move_to_next (tags))
\r
352 - fputs (format->tag_sep, stdout);
\r
353 - printf (format->tag, notmuch_tags_get (tags));
\r
355 + const char *tag = notmuch_tags_get (tags);
\r
357 + if (format->is_text_printer) {
\r
358 + /* Special case for the text formatter */
\r
360 + first_tag = FALSE;
\r
362 + fputc (' ', stdout);
\r
363 + fputs (tag, stdout);
\r
364 + } else { /* Structured Output */
\r
365 + format->string (format, tag);
\r
369 - fputs (format->tag_end, stdout);
\r
370 + if (format->is_text_printer)
\r
373 - fputs (format->item_end, stdout);
\r
374 + format->end (format);
\r
375 + format->end (format);
\r
376 + format->separator (format);
\r
379 - first_thread = 0;
\r
381 notmuch_thread_destroy (thread);
\r
384 - if (first_thread)
\r
385 - fputs (format->results_null, stdout);
\r
387 - fputs (format->results_end, stdout);
\r
388 + format->end (format);
\r
394 -do_search_messages (const search_format_t *format,
\r
395 +do_search_messages (sprinter_t *format,
\r
396 notmuch_query_t *query,
\r
399 @@ -297,7 +182,6 @@ do_search_messages (const search_format_t *format,
\r
400 notmuch_message_t *message;
\r
401 notmuch_messages_t *messages;
\r
402 notmuch_filenames_t *filenames;
\r
403 - int first_message = 1;
\r
407 @@ -310,7 +194,7 @@ do_search_messages (const search_format_t *format,
\r
408 if (messages == NULL)
\r
411 - fputs (format->results_start, stdout);
\r
412 + format->begin_list (format);
\r
415 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
\r
416 @@ -328,24 +212,17 @@ do_search_messages (const search_format_t *format,
\r
417 notmuch_filenames_valid (filenames);
\r
418 notmuch_filenames_move_to_next (filenames))
\r
420 - if (! first_message)
\r
421 - fputs (format->item_sep, stdout);
\r
423 - format->item_id (message, "",
\r
424 - notmuch_filenames_get (filenames));
\r
426 - first_message = 0;
\r
427 + format->string (format, notmuch_filenames_get (filenames));
\r
428 + format->separator (format);
\r
431 notmuch_filenames_destroy( filenames );
\r
433 } else { /* output == OUTPUT_MESSAGES */
\r
434 - if (! first_message)
\r
435 - fputs (format->item_sep, stdout);
\r
437 - format->item_id (message, "id:",
\r
438 - notmuch_message_get_message_id (message));
\r
439 - first_message = 0;
\r
440 + format->set_prefix (format, "id");
\r
441 + format->string (format,
\r
442 + notmuch_message_get_message_id (message));
\r
443 + format->separator (format);
\r
446 notmuch_message_destroy (message);
\r
447 @@ -353,23 +230,19 @@ do_search_messages (const search_format_t *format,
\r
449 notmuch_messages_destroy (messages);
\r
451 - if (first_message)
\r
452 - fputs (format->results_null, stdout);
\r
454 - fputs (format->results_end, stdout);
\r
455 + format->end (format);
\r
461 do_search_tags (notmuch_database_t *notmuch,
\r
462 - const search_format_t *format,
\r
463 + sprinter_t *format,
\r
464 notmuch_query_t *query)
\r
466 notmuch_messages_t *messages = NULL;
\r
467 notmuch_tags_t *tags;
\r
469 - int first_tag = 1;
\r
471 /* should the following only special case if no excluded terms
\r
473 @@ -387,7 +260,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
477 - fputs (format->results_start, stdout);
\r
478 + format->begin_list (format);
\r
481 notmuch_tags_valid (tags);
\r
482 @@ -395,12 +268,9 @@ do_search_tags (notmuch_database_t *notmuch,
\r
484 tag = notmuch_tags_get (tags);
\r
487 - fputs (format->item_sep, stdout);
\r
488 + format->string (format, tag);
\r
489 + format->separator (format);
\r
491 - format->item_id (tags, "", tag);
\r
496 notmuch_tags_destroy (tags);
\r
497 @@ -408,10 +278,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
499 notmuch_messages_destroy (messages);
\r
502 - fputs (format->results_null, stdout);
\r
504 - fputs (format->results_end, stdout);
\r
505 + format->end (format);
\r
509 @@ -430,7 +297,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
510 notmuch_query_t *query;
\r
512 notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
\r
513 - const search_format_t *format = &format_text;
\r
514 + sprinter_t *format = NULL;
\r
515 int opt_index, ret;
\r
516 output_t output = OUTPUT_SUMMARY;
\r
518 @@ -475,10 +342,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
520 switch (format_sel) {
\r
521 case NOTMUCH_FORMAT_TEXT:
\r
522 - format = &format_text;
\r
523 + format = sprinter_text_create (ctx, stdout);
\r
525 case NOTMUCH_FORMAT_JSON:
\r
526 - format = &format_json;
\r
527 + format = sprinter_json_create (ctx, stdout);
\r
531 @@ -546,5 +413,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
532 notmuch_query_destroy (query);
\r
533 notmuch_database_destroy (notmuch);
\r
535 + talloc_free (format);
\r
539 diff --git a/test/json b/test/json
\r
540 index 6439788..337b3f5 100755
\r
543 @@ -9,15 +9,16 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e
\r
545 test_begin_subtest "Search message: json"
\r
546 add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
\r
547 -output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
\r
548 +output=$(notmuch search --format=json "json-search-message" | notmuch_json_show_sanitize | notmuch_search_sanitize)
\r
549 test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
550 -\"timestamp\": 946728000,
\r
551 -\"date_relative\": \"2000-01-01\",
\r
554 -\"authors\": \"Notmuch Test Suite\",
\r
555 -\"subject\": \"json-search-subject\",
\r
556 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
557 + \"timestamp\": 946728000,
\r
558 + \"date_relative\": \"2000-01-01\",
\r
561 + \"authors\": \"Notmuch Test Suite\",
\r
562 + \"subject\": \"json-search-subject\",
\r
563 + \"tags\": [\"inbox\",
\r
566 test_begin_subtest "Show message: json, utf-8"
\r
567 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
568 @@ -39,14 +40,15 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":
\r
570 test_begin_subtest "Search message: json, utf-8"
\r
571 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
572 -output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
\r
573 +output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_json_show_sanitize | notmuch_search_sanitize)
\r
574 test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
575 -\"timestamp\": 946728000,
\r
576 -\"date_relative\": \"2000-01-01\",
\r
579 -\"authors\": \"Notmuch Test Suite\",
\r
580 -\"subject\": \"json-search-utf8-body-sübjéct\",
\r
581 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
582 + \"timestamp\": 946728000,
\r
583 + \"date_relative\": \"2000-01-01\",
\r
586 + \"authors\": \"Notmuch Test Suite\",
\r
587 + \"subject\": \"json-search-utf8-body-sübjéct\",
\r
588 + \"tags\": [\"inbox\",
\r