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 633D1431FC3
\r
6 for <notmuch@notmuchmail.org>; Mon, 16 Jul 2012 23:04:44 -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 MnJuyUM6qyfy for <notmuch@notmuchmail.org>;
\r
17 Mon, 16 Jul 2012 23:04:39 -0700 (PDT)
\r
18 Received: from mailout-de.gmx.net (mailout-de.gmx.net [213.165.64.23])
\r
19 by olra.theworths.org (Postfix) with SMTP id 1A2D1431FBC
\r
20 for <notmuch@notmuchmail.org>; Mon, 16 Jul 2012 23:04:36 -0700 (PDT)
\r
21 Received: (qmail invoked by alias); 17 Jul 2012 06:04:32 -0000
\r
22 Received: from gw.arelion.cust.net.lagis.at (EHLO dodekanex.arelion.at)
\r
24 by mail.gmx.net (mp027) with SMTP; 17 Jul 2012 08:04:32 +0200
\r
25 X-Authenticated: #201305
\r
26 X-Provags-ID: V01U2FsdGVkX1+PMTxuD7ePHfL+12nx6ttMCnC+sQvlSywu8iSV78
\r
28 Received: by dodekanex.arelion.at (Postfix, from userid 1000)
\r
29 id 1287A303542; Mon, 16 Jul 2012 10:35:05 +0200 (CEST)
\r
30 From: <craven@gmx.net>
\r
31 To: notmuch@notmuchmail.org
\r
32 Subject: [PATCH v6 3/3] Use the structured formatters in notmuch-search.c.
\r
33 Date: Mon, 16 Jul 2012 10:35:02 +0200
\r
34 Message-Id: <1342427702-23316-4-git-send-email-craven@gmx.net>
\r
35 X-Mailer: git-send-email 1.7.11.1
\r
36 In-Reply-To: <1342427702-23316-1-git-send-email-craven@gmx.net>
\r
37 References: <20120714020954.GD31670@mit.edu>
\r
38 <1342427702-23316-1-git-send-email-craven@gmx.net>
\r
40 Content-Type: text/plain; charset=UTF-8
\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: Tue, 17 Jul 2012 06:04:44 -0000
\r
57 This patch switches from the current ad-hoc printer to the structured
\r
58 formatters in sprinter.h, sprinter-text-search.c and sprinter-json.c.
\r
60 The JSON tests are changed slightly in order to make them PASS for the
\r
61 new structured output formatter.
\r
63 The text tests pass without adaptation.
\r
65 notmuch-search.c | 300 ++++++++++++++++---------------------------------------
\r
67 2 files changed, 86 insertions(+), 232 deletions(-)
\r
69 diff --git a/notmuch-search.c b/notmuch-search.c
\r
70 index 3be296d..cf927e6 100644
\r
71 --- a/notmuch-search.c
\r
72 +++ b/notmuch-search.c
\r
76 #include "notmuch-client.h"
\r
77 +#include "sprinter.h"
\r
81 @@ -28,92 +29,6 @@ typedef enum {
\r
85 -typedef struct search_format {
\r
86 - const char *results_start;
\r
87 - const char *item_start;
\r
88 - void (*item_id) (const void *ctx,
\r
89 - const char *item_type,
\r
90 - const char *item_id);
\r
91 - void (*thread_summary) (const void *ctx,
\r
92 - const char *thread_id,
\r
93 - const time_t date,
\r
94 - const int matched,
\r
96 - const char *authors,
\r
97 - const char *subject);
\r
98 - const char *tag_start;
\r
100 - const char *tag_sep;
\r
101 - const char *tag_end;
\r
102 - const char *item_sep;
\r
103 - const char *item_end;
\r
104 - const char *results_end;
\r
105 - const char *results_null;
\r
106 -} search_format_t;
\r
109 -format_item_id_text (const void *ctx,
\r
110 - const char *item_type,
\r
111 - const char *item_id);
\r
114 -format_thread_text (const void *ctx,
\r
115 - const char *thread_id,
\r
116 - const time_t date,
\r
117 - const int matched,
\r
119 - const char *authors,
\r
120 - const char *subject);
\r
121 -static const search_format_t format_text = {
\r
124 - format_item_id_text,
\r
125 - format_thread_text,
\r
135 -format_item_id_json (const void *ctx,
\r
136 - const char *item_type,
\r
137 - const char *item_id);
\r
140 -format_thread_json (const void *ctx,
\r
141 - const char *thread_id,
\r
142 - const time_t date,
\r
143 - const int matched,
\r
145 - const char *authors,
\r
146 - const char *subject);
\r
148 -/* Any changes to the JSON format should be reflected in the file
\r
149 - * devel/schemata. */
\r
150 -static const search_format_t format_json = {
\r
153 - format_item_id_json,
\r
154 - format_thread_json,
\r
164 -format_item_id_text (unused (const void *ctx),
\r
165 - const char *item_type,
\r
166 - const char *item_id)
\r
168 - printf ("%s%s", item_type, item_id);
\r
172 sanitize_string (const void *ctx, const char *str)
\r
174 @@ -131,72 +46,8 @@ sanitize_string (const void *ctx, const char *str)
\r
179 -format_thread_text (const void *ctx,
\r
180 - const char *thread_id,
\r
181 - const time_t date,
\r
182 - const int matched,
\r
184 - const char *authors,
\r
185 - const char *subject)
\r
187 - void *ctx_quote = talloc_new (ctx);
\r
189 - printf ("thread:%s %12s [%d/%d] %s; %s",
\r
191 - notmuch_time_relative_date (ctx, date),
\r
194 - sanitize_string (ctx_quote, authors),
\r
195 - sanitize_string (ctx_quote, subject));
\r
197 - talloc_free (ctx_quote);
\r
201 -format_item_id_json (const void *ctx,
\r
202 - unused (const char *item_type),
\r
203 - const char *item_id)
\r
205 - void *ctx_quote = talloc_new (ctx);
\r
207 - printf ("%s", json_quote_str (ctx_quote, item_id));
\r
209 - talloc_free (ctx_quote);
\r
214 -format_thread_json (const void *ctx,
\r
215 - const char *thread_id,
\r
216 - const time_t date,
\r
217 - const int matched,
\r
219 - const char *authors,
\r
220 - const char *subject)
\r
222 - void *ctx_quote = talloc_new (ctx);
\r
224 - printf ("\"thread\": %s,\n"
\r
225 - "\"timestamp\": %ld,\n"
\r
226 - "\"date_relative\": \"%s\",\n"
\r
227 - "\"matched\": %d,\n"
\r
228 - "\"total\": %d,\n"
\r
229 - "\"authors\": %s,\n"
\r
230 - "\"subject\": %s,\n",
\r
231 - json_quote_str (ctx_quote, thread_id),
\r
233 - notmuch_time_relative_date (ctx, date),
\r
236 - json_quote_str (ctx_quote, authors),
\r
237 - json_quote_str (ctx_quote, subject));
\r
239 - talloc_free (ctx_quote);
\r
243 -do_search_threads (const search_format_t *format,
\r
244 +do_search_threads (sprinter_t *format,
\r
245 notmuch_query_t *query,
\r
246 notmuch_sort_t sort,
\r
248 @@ -207,7 +58,6 @@ do_search_threads (const search_format_t *format,
\r
249 notmuch_threads_t *threads;
\r
250 notmuch_tags_t *tags;
\r
252 - int first_thread = 1;
\r
256 @@ -220,14 +70,12 @@ do_search_threads (const search_format_t *format,
\r
257 if (threads == NULL)
\r
260 - fputs (format->results_start, stdout);
\r
261 + format->begin_list (format);
\r
264 notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
\r
265 notmuch_threads_move_to_next (threads), i++)
\r
267 - int first_tag = 1;
\r
269 thread = notmuch_threads_get (threads);
\r
272 @@ -235,60 +83,96 @@ do_search_threads (const search_format_t *format,
\r
276 - if (! first_thread)
\r
277 - fputs (format->item_sep, stdout);
\r
279 if (output == OUTPUT_THREADS) {
\r
280 - format->item_id (thread, "thread:",
\r
281 - notmuch_thread_get_thread_id (thread));
\r
282 + format->set_prefix (format, "thread");
\r
283 + format->string (format,
\r
284 + notmuch_thread_get_thread_id (thread));
\r
285 + format->separator (format);
\r
286 } else { /* output == OUTPUT_SUMMARY */
\r
287 - fputs (format->item_start, stdout);
\r
288 + void *ctx_quote = talloc_new (thread);
\r
289 + const char *authors = notmuch_thread_get_authors (thread);
\r
290 + const char *subject = notmuch_thread_get_subject (thread);
\r
291 + const char *thread_id = notmuch_thread_get_thread_id (thread);
\r
292 + int matched = notmuch_thread_get_matched_messages (thread);
\r
293 + int total = notmuch_thread_get_total_messages (thread);
\r
294 + const char *relative_date = NULL;
\r
295 + notmuch_bool_t first_tag = TRUE;
\r
297 + format->begin_map (format);
\r
299 if (sort == NOTMUCH_SORT_OLDEST_FIRST)
\r
300 date = notmuch_thread_get_oldest_date (thread);
\r
302 date = notmuch_thread_get_newest_date (thread);
\r
304 - format->thread_summary (thread,
\r
305 - notmuch_thread_get_thread_id (thread),
\r
307 - notmuch_thread_get_matched_messages (thread),
\r
308 - notmuch_thread_get_total_messages (thread),
\r
309 - notmuch_thread_get_authors (thread),
\r
310 - notmuch_thread_get_subject (thread));
\r
311 + relative_date = notmuch_time_relative_date (ctx_quote, date);
\r
313 + if (format->is_text_printer (format)) {
\r
314 + /* Special case for the text formatter */
\r
315 + printf ("thread:%s %12s [%d/%d] %s; %s (",
\r
320 + sanitize_string (ctx_quote, authors),
\r
321 + sanitize_string (ctx_quote, subject));
\r
322 + } else { /* Structured Output */
\r
323 + format->map_key (format, "thread");
\r
324 + format->string (format, thread_id);
\r
325 + format->map_key (format, "timestamp");
\r
326 + format->integer (format, date);
\r
327 + format->map_key (format, "date_relative");
\r
328 + format->string (format, relative_date);
\r
329 + format->map_key (format, "matched");
\r
330 + format->integer (format, matched);
\r
331 + format->map_key (format, "total");
\r
332 + format->integer (format, total);
\r
333 + format->map_key (format, "authors");
\r
334 + format->string (format, authors);
\r
335 + format->map_key (format, "subject");
\r
336 + format->string (format, subject);
\r
339 + talloc_free (ctx_quote);
\r
341 - fputs (format->tag_start, stdout);
\r
342 + format->map_key (format, "tags");
\r
343 + format->begin_list (format);
\r
345 for (tags = notmuch_thread_get_tags (thread);
\r
346 notmuch_tags_valid (tags);
\r
347 notmuch_tags_move_to_next (tags))
\r
350 - fputs (format->tag_sep, stdout);
\r
351 - printf (format->tag, notmuch_tags_get (tags));
\r
353 + const char *tag = notmuch_tags_get (tags);
\r
355 + if (format->is_text_printer (format)) {
\r
356 + /* Special case for the text formatter */
\r
358 + first_tag = FALSE;
\r
360 + fputc (' ', stdout);
\r
361 + fputs (tag, stdout);
\r
362 + } else /* Structured Output */
\r
363 + format->string (format, tag);
\r
366 - fputs (format->tag_end, stdout);
\r
367 + if (format->is_text_printer (format))
\r
370 - fputs (format->item_end, stdout);
\r
371 + format->end (format);
\r
372 + format->end (format);
\r
373 + format->separator (format);
\r
376 - first_thread = 0;
\r
378 notmuch_thread_destroy (thread);
\r
381 - if (first_thread)
\r
382 - fputs (format->results_null, stdout);
\r
384 - fputs (format->results_end, stdout);
\r
385 + format->end (format);
\r
391 -do_search_messages (const search_format_t *format,
\r
392 +do_search_messages (sprinter_t *format,
\r
393 notmuch_query_t *query,
\r
396 @@ -297,7 +181,6 @@ do_search_messages (const search_format_t *format,
\r
397 notmuch_message_t *message;
\r
398 notmuch_messages_t *messages;
\r
399 notmuch_filenames_t *filenames;
\r
400 - int first_message = 1;
\r
404 @@ -310,7 +193,7 @@ do_search_messages (const search_format_t *format,
\r
405 if (messages == NULL)
\r
408 - fputs (format->results_start, stdout);
\r
409 + format->begin_list (format);
\r
412 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
\r
413 @@ -328,24 +211,17 @@ do_search_messages (const search_format_t *format,
\r
414 notmuch_filenames_valid (filenames);
\r
415 notmuch_filenames_move_to_next (filenames))
\r
417 - if (! first_message)
\r
418 - fputs (format->item_sep, stdout);
\r
420 - format->item_id (message, "",
\r
421 - notmuch_filenames_get (filenames));
\r
423 - first_message = 0;
\r
424 + format->string (format, notmuch_filenames_get (filenames));
\r
425 + format->separator (format);
\r
428 notmuch_filenames_destroy( filenames );
\r
430 } else { /* output == OUTPUT_MESSAGES */
\r
431 - if (! first_message)
\r
432 - fputs (format->item_sep, stdout);
\r
434 - format->item_id (message, "id:",
\r
435 - notmuch_message_get_message_id (message));
\r
436 - first_message = 0;
\r
437 + format->set_prefix (format, "id");
\r
438 + format->string (format,
\r
439 + notmuch_message_get_message_id (message));
\r
440 + format->separator (format);
\r
443 notmuch_message_destroy (message);
\r
444 @@ -353,23 +229,19 @@ do_search_messages (const search_format_t *format,
\r
446 notmuch_messages_destroy (messages);
\r
448 - if (first_message)
\r
449 - fputs (format->results_null, stdout);
\r
451 - fputs (format->results_end, stdout);
\r
452 + format->end (format);
\r
458 do_search_tags (notmuch_database_t *notmuch,
\r
459 - const search_format_t *format,
\r
460 + sprinter_t *format,
\r
461 notmuch_query_t *query)
\r
463 notmuch_messages_t *messages = NULL;
\r
464 notmuch_tags_t *tags;
\r
466 - int first_tag = 1;
\r
468 /* should the following only special case if no excluded terms
\r
470 @@ -387,7 +259,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
474 - fputs (format->results_start, stdout);
\r
475 + format->begin_list (format);
\r
478 notmuch_tags_valid (tags);
\r
479 @@ -395,12 +267,9 @@ do_search_tags (notmuch_database_t *notmuch,
\r
481 tag = notmuch_tags_get (tags);
\r
484 - fputs (format->item_sep, stdout);
\r
485 + format->string (format, tag);
\r
486 + format->separator (format);
\r
488 - format->item_id (tags, "", tag);
\r
493 notmuch_tags_destroy (tags);
\r
494 @@ -408,10 +277,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
496 notmuch_messages_destroy (messages);
\r
499 - fputs (format->results_null, stdout);
\r
501 - fputs (format->results_end, stdout);
\r
502 + format->end (format);
\r
506 @@ -430,7 +296,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
507 notmuch_query_t *query;
\r
509 notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
\r
510 - const search_format_t *format = &format_text;
\r
511 + sprinter_t *format = NULL;
\r
512 int opt_index, ret;
\r
513 output_t output = OUTPUT_SUMMARY;
\r
515 @@ -475,10 +341,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
517 switch (format_sel) {
\r
518 case NOTMUCH_FORMAT_TEXT:
\r
519 - format = &format_text;
\r
520 + format = sprinter_text_search_create (ctx, stdout);
\r
522 case NOTMUCH_FORMAT_JSON:
\r
523 - format = &format_json;
\r
524 + format = sprinter_json_create (ctx, stdout);
\r
528 @@ -546,5 +412,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
529 notmuch_query_destroy (query);
\r
530 notmuch_database_destroy (notmuch);
\r
532 + talloc_free (format);
\r
536 diff --git a/test/json b/test/json
\r
537 index 6439788..f0ebf08 100755
\r
540 @@ -10,14 +10,7 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e
\r
541 test_begin_subtest "Search message: json"
\r
542 add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
\r
543 output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
\r
544 -test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
545 -\"timestamp\": 946728000,
\r
546 -\"date_relative\": \"2000-01-01\",
\r
549 -\"authors\": \"Notmuch Test Suite\",
\r
550 -\"subject\": \"json-search-subject\",
\r
551 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
552 +test_expect_equal "$output" "[{\"thread\": \"XXX\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"matched\": 1, \"total\": 1, \"authors\": \"Notmuch Test Suite\", \"subject\": \"json-search-subject\", \"tags\": [\"inbox\", \"unread\"]}]"
\r
554 test_begin_subtest "Show message: json, utf-8"
\r
555 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
556 @@ -40,13 +33,6 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":
\r
557 test_begin_subtest "Search message: json, utf-8"
\r
558 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
559 output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)
\r
560 -test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
561 -\"timestamp\": 946728000,
\r
562 -\"date_relative\": \"2000-01-01\",
\r
565 -\"authors\": \"Notmuch Test Suite\",
\r
566 -\"subject\": \"json-search-utf8-body-sübjéct\",
\r
567 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
568 +test_expect_equal "$output" "[{\"thread\": \"XXX\", \"timestamp\": 946728000, \"date_relative\": \"2000-01-01\", \"matched\": 1, \"total\": 1, \"authors\": \"Notmuch Test Suite\", \"subject\": \"json-search-utf8-body-sübjéct\", \"tags\": [\"inbox\", \"unread\"]}]"
\r