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 6D371431FC4
\r
6 for <notmuch@notmuchmail.org>; Fri, 13 Jul 2012 01:13:40 -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 JiBEjdiRIsyC for <notmuch@notmuchmail.org>;
\r
17 Fri, 13 Jul 2012 01:13:38 -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 6F987431FB6
\r
20 for <notmuch@notmuchmail.org>; Fri, 13 Jul 2012 01:13:38 -0700 (PDT)
\r
21 Received: (qmail invoked by alias); 13 Jul 2012 08:13:36 -0000
\r
22 Received: from cm56-137-203.liwest.at (EHLO nexork.localdomain)
\r
23 [86.56.137.203] by mail.gmx.net (mp031) with SMTP; 13 Jul 2012 10:13:36 +0200
\r
24 X-Authenticated: #201305
\r
25 X-Provags-ID: V01U2FsdGVkX1/5F15BT5z551ssTzEHrq20STEwd2BcyXuKZgG0aZ
\r
27 Received: by nexork.localdomain (Postfix, from userid 1000)
\r
28 id DFC714527804; Fri, 13 Jul 2012 10:11:42 +0200 (CEST)
\r
29 From: Peter Feigl <craven@gmx.net>
\r
30 To: notmuch@notmuchmail.org
\r
31 Subject: [PATCH v5 3/3] Use the structured formatters in notmuch-search.c.
\r
32 Date: Fri, 13 Jul 2012 10:11:37 +0200
\r
33 Message-Id: <1342167097-25012-4-git-send-email-craven@gmx.net>
\r
34 X-Mailer: git-send-email 1.7.11.1
\r
35 In-Reply-To: <1342167097-25012-1-git-send-email-craven@gmx.net>
\r
36 References: <20120710191331.GE7332@mit.edu>
\r
37 <1342167097-25012-1-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, 13 Jul 2012 08:13:40 -0000
\r
56 From: <craven@gmx.net>
\r
58 This patch switches from the current ad-hoc printer to the structured
\r
59 output formatter in sprinter.h, sprinter-text-search.c and
\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 | 292 +++++++++++--------------------------------------------
\r
69 2 files changed, 58 insertions(+), 252 deletions(-)
\r
71 diff --git a/notmuch-search.c b/notmuch-search.c
\r
72 index 3be296d..99fddac 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,175 +29,8 @@ 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 - char *out, *loop;
\r
181 - loop = out = talloc_strdup (ctx, str);
\r
183 - for (; *loop; loop++) {
\r
184 - if ((unsigned char)(*loop) < 32)
\r
191 -format_thread_text (const void *ctx,
\r
192 - const char *thread_id,
\r
193 - const time_t date,
\r
194 - const int matched,
\r
196 - const char *authors,
\r
197 - const char *subject)
\r
199 - void *ctx_quote = talloc_new (ctx);
\r
201 - printf ("thread:%s %12s [%d/%d] %s; %s",
\r
203 - notmuch_time_relative_date (ctx, date),
\r
206 - sanitize_string (ctx_quote, authors),
\r
207 - sanitize_string (ctx_quote, subject));
\r
209 - talloc_free (ctx_quote);
\r
213 -format_item_id_json (const void *ctx,
\r
214 - unused (const char *item_type),
\r
215 - const char *item_id)
\r
217 - void *ctx_quote = talloc_new (ctx);
\r
219 - printf ("%s", json_quote_str (ctx_quote, item_id));
\r
221 - talloc_free (ctx_quote);
\r
226 -format_thread_json (const void *ctx,
\r
227 - const char *thread_id,
\r
228 - const time_t date,
\r
229 - const int matched,
\r
231 - const char *authors,
\r
232 - const char *subject)
\r
234 - void *ctx_quote = talloc_new (ctx);
\r
236 - printf ("\"thread\": %s,\n"
\r
237 - "\"timestamp\": %ld,\n"
\r
238 - "\"date_relative\": \"%s\",\n"
\r
239 - "\"matched\": %d,\n"
\r
240 - "\"total\": %d,\n"
\r
241 - "\"authors\": %s,\n"
\r
242 - "\"subject\": %s,\n",
\r
243 - json_quote_str (ctx_quote, thread_id),
\r
245 - notmuch_time_relative_date (ctx, date),
\r
248 - json_quote_str (ctx_quote, authors),
\r
249 - json_quote_str (ctx_quote, subject));
\r
251 - talloc_free (ctx_quote);
\r
255 -do_search_threads (const search_format_t *format,
\r
256 +do_search_threads (sprinter_t *format,
\r
257 notmuch_query_t *query,
\r
258 notmuch_sort_t sort,
\r
260 @@ -207,7 +41,6 @@ do_search_threads (const search_format_t *format,
\r
261 notmuch_threads_t *threads;
\r
262 notmuch_tags_t *tags;
\r
264 - int first_thread = 1;
\r
268 @@ -220,14 +53,12 @@ do_search_threads (const search_format_t *format,
\r
269 if (threads == NULL)
\r
272 - fputs (format->results_start, stdout);
\r
273 + format->begin_list (format);
\r
276 notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);
\r
277 notmuch_threads_move_to_next (threads), i++)
\r
279 - int first_tag = 1;
\r
281 thread = notmuch_threads_get (threads);
\r
284 @@ -235,60 +66,65 @@ do_search_threads (const search_format_t *format,
\r
288 - if (! first_thread)
\r
289 - fputs (format->item_sep, stdout);
\r
291 if (output == OUTPUT_THREADS) {
\r
292 - format->item_id (thread, "thread:",
\r
293 - notmuch_thread_get_thread_id (thread));
\r
294 + format->set_prefix (format, "thread");
\r
295 + format->string (format,
\r
296 + notmuch_thread_get_thread_id (thread));
\r
297 + format->separator (format);
\r
298 } else { /* output == OUTPUT_SUMMARY */
\r
299 - fputs (format->item_start, stdout);
\r
300 + void *ctx_quote = talloc_new (thread);
\r
302 + format->begin_map (format);
\r
304 if (sort == NOTMUCH_SORT_OLDEST_FIRST)
\r
305 date = notmuch_thread_get_oldest_date (thread);
\r
307 date = notmuch_thread_get_newest_date (thread);
\r
309 - format->thread_summary (thread,
\r
310 - notmuch_thread_get_thread_id (thread),
\r
312 - notmuch_thread_get_matched_messages (thread),
\r
313 - notmuch_thread_get_total_messages (thread),
\r
314 - notmuch_thread_get_authors (thread),
\r
315 - notmuch_thread_get_subject (thread));
\r
317 - fputs (format->tag_start, stdout);
\r
318 + format->map_key (format, "thread");
\r
319 + format->string (format, notmuch_thread_get_thread_id (thread));
\r
320 + format->map_key (format, "timestamp");
\r
321 + format->integer (format, date);
\r
322 + format->map_key (format, "date_relative");
\r
323 + format->string (format, notmuch_time_relative_date (ctx_quote, date));
\r
324 + format->map_key (format, "matched");
\r
325 + format->integer (format, notmuch_thread_get_matched_messages (thread));
\r
326 + format->map_key (format, "total");
\r
327 + format->integer (format, notmuch_thread_get_total_messages (thread));
\r
328 + format->map_key (format, "authors");
\r
329 + format->string (format, notmuch_thread_get_authors (thread));
\r
330 + format->map_key (format, "subject");
\r
331 + format->string (format, notmuch_thread_get_subject (thread));
\r
333 + talloc_free (ctx_quote);
\r
335 + format->map_key (format, "tags");
\r
336 + format->begin_list (format);
\r
338 for (tags = notmuch_thread_get_tags (thread);
\r
339 notmuch_tags_valid (tags);
\r
340 notmuch_tags_move_to_next (tags))
\r
343 - fputs (format->tag_sep, stdout);
\r
344 - printf (format->tag, notmuch_tags_get (tags));
\r
347 + const char *tag = notmuch_tags_get (tags);
\r
349 - fputs (format->tag_end, stdout);
\r
350 + format->string (format, tag);
\r
353 - fputs (format->item_end, stdout);
\r
354 + format->end (format);
\r
355 + format->end (format);
\r
356 + format->separator (format);
\r
359 - first_thread = 0;
\r
361 notmuch_thread_destroy (thread);
\r
364 - if (first_thread)
\r
365 - fputs (format->results_null, stdout);
\r
367 - fputs (format->results_end, stdout);
\r
368 + format->end (format);
\r
374 -do_search_messages (const search_format_t *format,
\r
375 +do_search_messages (sprinter_t *format,
\r
376 notmuch_query_t *query,
\r
379 @@ -297,7 +133,6 @@ do_search_messages (const search_format_t *format,
\r
380 notmuch_message_t *message;
\r
381 notmuch_messages_t *messages;
\r
382 notmuch_filenames_t *filenames;
\r
383 - int first_message = 1;
\r
387 @@ -310,7 +145,7 @@ do_search_messages (const search_format_t *format,
\r
388 if (messages == NULL)
\r
391 - fputs (format->results_start, stdout);
\r
392 + format->begin_list (format);
\r
395 notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);
\r
396 @@ -328,24 +163,17 @@ do_search_messages (const search_format_t *format,
\r
397 notmuch_filenames_valid (filenames);
\r
398 notmuch_filenames_move_to_next (filenames))
\r
400 - if (! first_message)
\r
401 - fputs (format->item_sep, stdout);
\r
403 - format->item_id (message, "",
\r
404 - notmuch_filenames_get (filenames));
\r
406 - first_message = 0;
\r
407 + format->string (format, notmuch_filenames_get (filenames));
\r
408 + format->separator (format);
\r
412 notmuch_filenames_destroy( filenames );
\r
414 } else { /* output == OUTPUT_MESSAGES */
\r
415 - if (! first_message)
\r
416 - fputs (format->item_sep, stdout);
\r
418 - format->item_id (message, "id:",
\r
419 - notmuch_message_get_message_id (message));
\r
420 - first_message = 0;
\r
421 + format->set_prefix (format, "id");
\r
422 + format->string (format,
\r
423 + notmuch_message_get_message_id (message));
\r
424 + format->separator (format);
\r
427 notmuch_message_destroy (message);
\r
428 @@ -353,23 +181,19 @@ do_search_messages (const search_format_t *format,
\r
430 notmuch_messages_destroy (messages);
\r
432 - if (first_message)
\r
433 - fputs (format->results_null, stdout);
\r
435 - fputs (format->results_end, stdout);
\r
436 + format->end (format);
\r
442 do_search_tags (notmuch_database_t *notmuch,
\r
443 - const search_format_t *format,
\r
444 + sprinter_t *format,
\r
445 notmuch_query_t *query)
\r
447 notmuch_messages_t *messages = NULL;
\r
448 notmuch_tags_t *tags;
\r
450 - int first_tag = 1;
\r
452 /* should the following only special case if no excluded terms
\r
454 @@ -387,7 +211,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
458 - fputs (format->results_start, stdout);
\r
459 + format->begin_list (format);
\r
462 notmuch_tags_valid (tags);
\r
463 @@ -395,12 +219,9 @@ do_search_tags (notmuch_database_t *notmuch,
\r
465 tag = notmuch_tags_get (tags);
\r
468 - fputs (format->item_sep, stdout);
\r
469 + format->string (format, tag);
\r
470 + format->separator (format);
\r
472 - format->item_id (tags, "", tag);
\r
477 notmuch_tags_destroy (tags);
\r
478 @@ -408,10 +229,7 @@ do_search_tags (notmuch_database_t *notmuch,
\r
480 notmuch_messages_destroy (messages);
\r
483 - fputs (format->results_null, stdout);
\r
485 - fputs (format->results_end, stdout);
\r
486 + format->end (format);
\r
490 @@ -430,7 +248,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
491 notmuch_query_t *query;
\r
493 notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;
\r
494 - const search_format_t *format = &format_text;
\r
495 + sprinter_t *format = NULL;
\r
496 int opt_index, ret;
\r
497 output_t output = OUTPUT_SUMMARY;
\r
499 @@ -475,10 +293,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
501 switch (format_sel) {
\r
502 case NOTMUCH_FORMAT_TEXT:
\r
503 - format = &format_text;
\r
504 + format = sprinter_text_search_create (ctx, stdout);
\r
506 case NOTMUCH_FORMAT_JSON:
\r
507 - format = &format_json;
\r
508 + format = sprinter_json_create (ctx, stdout);
\r
512 @@ -546,5 +364,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
\r
513 notmuch_query_destroy (query);
\r
514 notmuch_database_destroy (notmuch);
\r
516 + talloc_free (format);
\r
520 diff --git a/test/json b/test/json
\r
521 index 6439788..f0ebf08 100755
\r
524 @@ -10,14 +10,7 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e
\r
525 test_begin_subtest "Search message: json"
\r
526 add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""
\r
527 output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)
\r
528 -test_expect_equal "$output" "[{\"thread\": \"XXX\",
\r
529 -\"timestamp\": 946728000,
\r
530 -\"date_relative\": \"2000-01-01\",
\r
533 -\"authors\": \"Notmuch Test Suite\",
\r
534 -\"subject\": \"json-search-subject\",
\r
535 -\"tags\": [\"inbox\", \"unread\"]}]"
\r
536 +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
538 test_begin_subtest "Show message: json, utf-8"
\r
539 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
540 @@ -40,13 +33,6 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":
\r
541 test_begin_subtest "Search message: json, utf-8"
\r
542 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
543 output=$(notmuch search --format=json "jsön-search-méssage" | 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-utf8-body-sübjéct\",
\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-utf8-body-sübjéct\", \"tags\": [\"inbox\", \"unread\"]}]"
\r