Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / 5a / 6269bacb11cc7e8f2506263ddb6aa87e518b83
1 Return-Path: <amdragon@mit.edu>\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 9D7D8431FB6\r
6         for <notmuch@notmuchmail.org>; Fri, 13 Jul 2012 19:09:59 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id uXg3NFNtSJQX for <notmuch@notmuchmail.org>;\r
16         Fri, 13 Jul 2012 19:09:57 -0700 (PDT)\r
17 Received: from dmz-mailsec-scanner-7.mit.edu (DMZ-MAILSEC-SCANNER-7.MIT.EDU\r
18         [18.7.68.36])\r
19         by olra.theworths.org (Postfix) with ESMTP id A22E8431FAE\r
20         for <notmuch@notmuchmail.org>; Fri, 13 Jul 2012 19:09:57 -0700 (PDT)\r
21 X-AuditID: 12074424-b7f2a6d0000008bf-16-5000d4f548e4\r
22 Received: from mailhub-auth-1.mit.edu ( [18.9.21.35])\r
23         by dmz-mailsec-scanner-7.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id D6.1C.02239.5F4D0005; Fri, 13 Jul 2012 22:09:57 -0400 (EDT)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-1.mit.edu (8.13.8/8.9.2) with ESMTP id q6E29ukA022868; \r
27         Fri, 13 Jul 2012 22:09:56 -0400\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q6E29tcc009849\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Fri, 13 Jul 2012 22:09:55 -0400 (EDT)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)\r
35         (envelope-from <amdragon@mit.edu>)\r
36         id 1Sprnu-0000f4-Sr; Fri, 13 Jul 2012 22:09:54 -0400\r
37 Date: Fri, 13 Jul 2012 22:09:54 -0400\r
38 From: Austin Clements <amdragon@MIT.EDU>\r
39 To: Peter Feigl <craven@gmx.net>\r
40 Subject: Re: [PATCH v5 3/3] Use the structured formatters in notmuch-search.c.\r
41 Message-ID: <20120714020954.GD31670@mit.edu>\r
42 References: <20120710191331.GE7332@mit.edu>\r
43         <1342167097-25012-1-git-send-email-craven@gmx.net>\r
44         <1342167097-25012-4-git-send-email-craven@gmx.net>\r
45 MIME-Version: 1.0\r
46 Content-Type: text/plain; charset=iso-8859-1\r
47 Content-Disposition: inline\r
48 Content-Transfer-Encoding: 8bit\r
49 In-Reply-To: <1342167097-25012-4-git-send-email-craven@gmx.net>\r
50 User-Agent: Mutt/1.5.21 (2010-09-15)\r
51 X-Brightmail-Tracker:\r
52  H4sIAAAAAAAAA+NgFprDKsWRmVeSWpSXmKPExsUixCmqrPv1CkOAwcqtHBZ7G9oZLa7fnMns\r
53         wOSxeNN+No9nq24xBzBFcdmkpOZklqUW6dslcGX8vXiSuWBKXcXnm2tZGxjnxXcxcnBICJhI\r
54         rP4j2MXICWSKSVy4t56ti5GLQ0hgH6PEp9bPUM4GRomVDyayQjgnmSRmbbgK5SxhlPjx/Asz\r
55         SD+LgKrEmpmbWUBsNgENiW37lzOC2CICChLP1jWB2cwC0hLffjczgdjCAn4SFxb1soHYvAI6\r
56         Ept372GEGDqVUWLeit+MEAlBiZMzn7BANOtI7Nx6hw3kbpBBy/9xQITlJZq3zga7gVPAXuLq\r
57         6s3sILaogIrElJPb2CYwCs9CMmkWkkmzECbNQjJpASPLKkbZlNwq3dzEzJzi1GTd4uTEvLzU\r
58         Il1zvdzMEr3UlNJNjKBIYHdR2cHYfEjpEKMAB6MSD2+SP0OAEGtiWXFl7iFGSQ4mJVHeWReB\r
59         QnxJ+SmVGYnFGfFFpTmpxYcYJTiYlUR4zduAcrwpiZVVqUX5MClpDhYlcd7rKTf9hQTSE0tS\r
60         s1NTC1KLYLIyHBxKEryFwIgXEixKTU+tSMvMKUFIM3FwggznARreAlLDW1yQmFucmQ6RP8Wo\r
61         KCXOGwKSEABJZJTmwfXCEtUrRnGgV4R540GqeIBJDq77FdBgJqDBs37+8wcaXJKIkJJqYDT5\r
62         zDhXLax3wr8rR6Mn7fv3RcXMPXfe9DunHMucw3dNL3T7tKZ9W+LNpfHNp80t98+awbA77zO/\r
63         v5IOf0BGftLFKx1zF0xe8KfqSK3bH3/vGfy/vJvub5i5ZottlV7GDE3pPmPJG86LlPa4PE2y\r
64         l5P+dSZa/rZ28PulWf9X7GFqfvS+pzRrSq0SS3FGoqEWc1FxIgDICgKQLwMAAA==\r
65 Cc: notmuch@notmuchmail.org\r
66 X-BeenThere: notmuch@notmuchmail.org\r
67 X-Mailman-Version: 2.1.13\r
68 Precedence: list\r
69 List-Id: "Use and development of the notmuch mail system."\r
70         <notmuch.notmuchmail.org>\r
71 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
72         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
73 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
74 List-Post: <mailto:notmuch@notmuchmail.org>\r
75 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
76 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
77         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
78 X-List-Received-Date: Sat, 14 Jul 2012 02:09:59 -0000\r
79 \r
80 Just one comment below.  Otherwise this patch LGTM (though some of my\r
81 comments on the previous patch will affect this one).  It's nice to\r
82 see all of that old newline logic disappear.\r
83 \r
84 Quoth Peter Feigl on Jul 13 at 10:11 am:\r
85 > From: <craven@gmx.net>\r
86\r
87 > This patch switches from the current ad-hoc printer to the structured\r
88 > output formatter in sprinter.h, sprinter-text-search.c and\r
89 > sprinter-json.c.\r
90\r
91 > The JSON tests are changed slightly in order to make them PASS for the\r
92 > new structured output formatter.\r
93\r
94 > The Text tests pass without adaptation.\r
95 > ---\r
96 >  notmuch-search.c | 292 +++++++++++--------------------------------------------\r
97 >  test/json        |  18 +---\r
98 >  2 files changed, 58 insertions(+), 252 deletions(-)\r
99\r
100 > diff --git a/notmuch-search.c b/notmuch-search.c\r
101 > index 3be296d..99fddac 100644\r
102 > --- a/notmuch-search.c\r
103 > +++ b/notmuch-search.c\r
104 > @@ -19,6 +19,7 @@\r
105 >   */\r
106 >  \r
107 >  #include "notmuch-client.h"\r
108 > +#include "sprinter.h"\r
109 >  \r
110 >  typedef enum {\r
111 >      OUTPUT_SUMMARY,\r
112 > @@ -28,175 +29,8 @@ typedef enum {\r
113 >      OUTPUT_TAGS\r
114 >  } output_t;\r
115 >  \r
116 > -typedef struct search_format {\r
117 > -    const char *results_start;\r
118 > -    const char *item_start;\r
119 > -    void (*item_id) (const void *ctx,\r
120 > -                  const char *item_type,\r
121 > -                  const char *item_id);\r
122 > -    void (*thread_summary) (const void *ctx,\r
123 > -                         const char *thread_id,\r
124 > -                         const time_t date,\r
125 > -                         const int matched,\r
126 > -                         const int total,\r
127 > -                         const char *authors,\r
128 > -                         const char *subject);\r
129 > -    const char *tag_start;\r
130 > -    const char *tag;\r
131 > -    const char *tag_sep;\r
132 > -    const char *tag_end;\r
133 > -    const char *item_sep;\r
134 > -    const char *item_end;\r
135 > -    const char *results_end;\r
136 > -    const char *results_null;\r
137 > -} search_format_t;\r
138 > -\r
139 > -static void\r
140 > -format_item_id_text (const void *ctx,\r
141 > -                  const char *item_type,\r
142 > -                  const char *item_id);\r
143 > -\r
144 > -static void\r
145 > -format_thread_text (const void *ctx,\r
146 > -                 const char *thread_id,\r
147 > -                 const time_t date,\r
148 > -                 const int matched,\r
149 > -                 const int total,\r
150 > -                 const char *authors,\r
151 > -                 const char *subject);\r
152 > -static const search_format_t format_text = {\r
153 > -    "",\r
154 > -     "",\r
155 > -         format_item_id_text,\r
156 > -         format_thread_text,\r
157 > -         " (",\r
158 > -             "%s", " ",\r
159 > -         ")", "\n",\r
160 > -     "",\r
161 > -    "\n",\r
162 > -    "",\r
163 > -};\r
164 > -\r
165 > -static void\r
166 > -format_item_id_json (const void *ctx,\r
167 > -                  const char *item_type,\r
168 > -                  const char *item_id);\r
169 > -\r
170 > -static void\r
171 > -format_thread_json (const void *ctx,\r
172 > -                 const char *thread_id,\r
173 > -                 const time_t date,\r
174 > -                 const int matched,\r
175 > -                 const int total,\r
176 > -                 const char *authors,\r
177 > -                 const char *subject);\r
178 > -\r
179 > -/* Any changes to the JSON format should be reflected in the file\r
180 > - * devel/schemata. */\r
181 > -static const search_format_t format_json = {\r
182 > -    "[",\r
183 > -     "{",\r
184 > -         format_item_id_json,\r
185 > -         format_thread_json,\r
186 > -         "\"tags\": [",\r
187 > -             "\"%s\"", ", ",\r
188 > -         "]", ",\n",\r
189 > -     "}",\r
190 > -    "]\n",\r
191 > -    "]\n",\r
192 > -};\r
193 > -\r
194 > -static void\r
195 > -format_item_id_text (unused (const void *ctx),\r
196 > -                  const char *item_type,\r
197 > -                  const char *item_id)\r
198 > -{\r
199 > -    printf ("%s%s", item_type, item_id);\r
200 > -}\r
201 > -\r
202 > -static char *\r
203 > -sanitize_string (const void *ctx, const char *str)\r
204 > -{\r
205 > -    char *out, *loop;\r
206 > -\r
207 > -    if (NULL == str)\r
208 > -     return NULL;\r
209 > -\r
210 > -    loop = out = talloc_strdup (ctx, str);\r
211 > -\r
212 > -    for (; *loop; loop++) {\r
213 > -     if ((unsigned char)(*loop) < 32)\r
214 > -         *loop = '?';\r
215 > -    }\r
216 > -    return out;\r
217 > -}\r
218 > -\r
219 > -static void\r
220 > -format_thread_text (const void *ctx,\r
221 > -                 const char *thread_id,\r
222 > -                 const time_t date,\r
223 > -                 const int matched,\r
224 > -                 const int total,\r
225 > -                 const char *authors,\r
226 > -                 const char *subject)\r
227 > -{\r
228 > -    void *ctx_quote = talloc_new (ctx);\r
229 > -\r
230 > -    printf ("thread:%s %12s [%d/%d] %s; %s",\r
231 > -         thread_id,\r
232 > -         notmuch_time_relative_date (ctx, date),\r
233 > -         matched,\r
234 > -         total,\r
235 > -         sanitize_string (ctx_quote, authors),\r
236 > -         sanitize_string (ctx_quote, subject));\r
237 > -\r
238 > -    talloc_free (ctx_quote);\r
239 > -}\r
240 > -\r
241 > -static void\r
242 > -format_item_id_json (const void *ctx,\r
243 > -                  unused (const char *item_type),\r
244 > -                  const char *item_id)\r
245 > -{\r
246 > -    void *ctx_quote = talloc_new (ctx);\r
247 > -\r
248 > -    printf ("%s", json_quote_str (ctx_quote, item_id));\r
249 > -\r
250 > -    talloc_free (ctx_quote);\r
251 > -    \r
252 > -}\r
253 > -\r
254 > -static void\r
255 > -format_thread_json (const void *ctx,\r
256 > -                 const char *thread_id,\r
257 > -                 const time_t date,\r
258 > -                 const int matched,\r
259 > -                 const int total,\r
260 > -                 const char *authors,\r
261 > -                 const char *subject)\r
262 > -{\r
263 > -    void *ctx_quote = talloc_new (ctx);\r
264 > -\r
265 > -    printf ("\"thread\": %s,\n"\r
266 > -         "\"timestamp\": %ld,\n"\r
267 > -         "\"date_relative\": \"%s\",\n"\r
268 > -         "\"matched\": %d,\n"\r
269 > -         "\"total\": %d,\n"\r
270 > -         "\"authors\": %s,\n"\r
271 > -         "\"subject\": %s,\n",\r
272 > -         json_quote_str (ctx_quote, thread_id),\r
273 > -         date,\r
274 > -         notmuch_time_relative_date (ctx, date),\r
275 > -         matched,\r
276 > -         total,\r
277 > -         json_quote_str (ctx_quote, authors),\r
278 > -         json_quote_str (ctx_quote, subject));\r
279 > -\r
280 > -    talloc_free (ctx_quote);\r
281 > -}\r
282 > -\r
283 >  static int\r
284 > -do_search_threads (const search_format_t *format,\r
285 > +do_search_threads (sprinter_t *format,\r
286 >                  notmuch_query_t *query,\r
287 >                  notmuch_sort_t sort,\r
288 >                  output_t output,\r
289 > @@ -207,7 +41,6 @@ do_search_threads (const search_format_t *format,\r
290 >      notmuch_threads_t *threads;\r
291 >      notmuch_tags_t *tags;\r
292 >      time_t date;\r
293 > -    int first_thread = 1;\r
294 >      int i;\r
295 >  \r
296 >      if (offset < 0) {\r
297 > @@ -220,14 +53,12 @@ do_search_threads (const search_format_t *format,\r
298 >      if (threads == NULL)\r
299 >       return 1;\r
300 >  \r
301 > -    fputs (format->results_start, stdout);\r
302 > +    format->begin_list (format);\r
303 >  \r
304 >      for (i = 0;\r
305 >        notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);\r
306 >        notmuch_threads_move_to_next (threads), i++)\r
307 >      {\r
308 > -     int first_tag = 1;\r
309 > -\r
310 >       thread = notmuch_threads_get (threads);\r
311 >  \r
312 >       if (i < offset) {\r
313 > @@ -235,60 +66,65 @@ do_search_threads (const search_format_t *format,\r
314 >           continue;\r
315 >       }\r
316 >  \r
317 > -     if (! first_thread)\r
318 > -         fputs (format->item_sep, stdout);\r
319 > -\r
320 >       if (output == OUTPUT_THREADS) {\r
321 > -         format->item_id (thread, "thread:",\r
322 > -                          notmuch_thread_get_thread_id (thread));\r
323 > +         format->set_prefix (format, "thread");\r
324 > +         format->string (format,\r
325 > +                         notmuch_thread_get_thread_id (thread));\r
326 > +         format->separator (format);\r
327 >       } else { /* output == OUTPUT_SUMMARY */\r
328 > -         fputs (format->item_start, stdout);\r
329 > +         void *ctx_quote = talloc_new (thread);\r
330 > +\r
331 > +         format->begin_map (format);\r
332 >  \r
333 >           if (sort == NOTMUCH_SORT_OLDEST_FIRST)\r
334 >               date = notmuch_thread_get_oldest_date (thread);\r
335 >           else\r
336 >               date = notmuch_thread_get_newest_date (thread);\r
337 >  \r
338 > -         format->thread_summary (thread,\r
339 > -                                 notmuch_thread_get_thread_id (thread),\r
340 > -                                 date,\r
341 > -                                 notmuch_thread_get_matched_messages (thread),\r
342 > -                                 notmuch_thread_get_total_messages (thread),\r
343 > -                                 notmuch_thread_get_authors (thread),\r
344 > -                                 notmuch_thread_get_subject (thread));\r
345 > -\r
346 > -         fputs (format->tag_start, stdout);\r
347 > +         format->map_key (format, "thread");\r
348 > +         format->string (format, notmuch_thread_get_thread_id (thread));\r
349 > +         format->map_key (format, "timestamp");\r
350 > +         format->integer (format, date);\r
351 > +         format->map_key (format, "date_relative");\r
352 > +         format->string (format, notmuch_time_relative_date (ctx_quote, date));\r
353 > +         format->map_key (format, "matched");\r
354 > +         format->integer (format, notmuch_thread_get_matched_messages (thread));\r
355 > +         format->map_key (format, "total");\r
356 > +         format->integer (format, notmuch_thread_get_total_messages (thread));\r
357 > +         format->map_key (format, "authors");\r
358 > +         format->string (format, notmuch_thread_get_authors (thread));\r
359 > +         format->map_key (format, "subject");\r
360 > +         format->string (format, notmuch_thread_get_subject (thread));\r
361 > +\r
362 > +         talloc_free (ctx_quote);\r
363 > +\r
364 > +         format->map_key (format, "tags");\r
365 > +         format->begin_list (format);\r
366 >  \r
367 >           for (tags = notmuch_thread_get_tags (thread);\r
368 >                notmuch_tags_valid (tags);\r
369 >                notmuch_tags_move_to_next (tags))\r
370 >           {\r
371 > -             if (! first_tag)\r
372 > -                 fputs (format->tag_sep, stdout);\r
373 > -             printf (format->tag, notmuch_tags_get (tags));\r
374 > -             first_tag = 0;\r
375 > -         }\r
376 > +             const char *tag = notmuch_tags_get (tags);\r
377 >  \r
378 > -         fputs (format->tag_end, stdout);\r
379 > +             format->string (format, tag);\r
380 > +         }\r
381 >  \r
382 > -         fputs (format->item_end, stdout);\r
383 > +         format->end (format);\r
384 > +         format->end (format);\r
385 > +         format->separator (format);\r
386 >       }\r
387 >  \r
388 > -     first_thread = 0;\r
389 > -\r
390 >       notmuch_thread_destroy (thread);\r
391 >      }\r
392 >  \r
393 > -    if (first_thread)\r
394 > -     fputs (format->results_null, stdout);\r
395 > -    else\r
396 > -     fputs (format->results_end, stdout);\r
397 > +    format->end (format);\r
398 >  \r
399 >      return 0;\r
400 >  }\r
401 >  \r
402 >  static int\r
403 > -do_search_messages (const search_format_t *format,\r
404 > +do_search_messages (sprinter_t *format,\r
405 >                   notmuch_query_t *query,\r
406 >                   output_t output,\r
407 >                   int offset,\r
408 > @@ -297,7 +133,6 @@ do_search_messages (const search_format_t *format,\r
409 >      notmuch_message_t *message;\r
410 >      notmuch_messages_t *messages;\r
411 >      notmuch_filenames_t *filenames;\r
412 > -    int first_message = 1;\r
413 >      int i;\r
414 >  \r
415 >      if (offset < 0) {\r
416 > @@ -310,7 +145,7 @@ do_search_messages (const search_format_t *format,\r
417 >      if (messages == NULL)\r
418 >       return 1;\r
419 >  \r
420 > -    fputs (format->results_start, stdout);\r
421 > +    format->begin_list (format);\r
422 >  \r
423 >      for (i = 0;\r
424 >        notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);\r
425 > @@ -328,24 +163,17 @@ do_search_messages (const search_format_t *format,\r
426 >                notmuch_filenames_valid (filenames);\r
427 >                notmuch_filenames_move_to_next (filenames))\r
428 >           {\r
429 > -             if (! first_message)\r
430 > -                 fputs (format->item_sep, stdout);\r
431 > -\r
432 > -             format->item_id (message, "",\r
433 > -                              notmuch_filenames_get (filenames));\r
434 > -\r
435 > -             first_message = 0;\r
436 > +             format->string (format, notmuch_filenames_get (filenames));\r
437 > +             format->separator (format);\r
438 >           }\r
439 > -         \r
440 > +\r
441 >           notmuch_filenames_destroy( filenames );\r
442 >  \r
443 >       } else { /* output == OUTPUT_MESSAGES */\r
444 > -         if (! first_message)\r
445 > -             fputs (format->item_sep, stdout);\r
446 > -\r
447 > -         format->item_id (message, "id:",\r
448 > -                          notmuch_message_get_message_id (message));\r
449 > -         first_message = 0;\r
450 > +         format->set_prefix (format, "id");\r
451 > +         format->string (format,\r
452 > +                         notmuch_message_get_message_id (message));\r
453 > +         format->separator (format);\r
454 >       }\r
455 >  \r
456 >       notmuch_message_destroy (message);\r
457 > @@ -353,23 +181,19 @@ do_search_messages (const search_format_t *format,\r
458 >  \r
459 >      notmuch_messages_destroy (messages);\r
460 >  \r
461 > -    if (first_message)\r
462 > -     fputs (format->results_null, stdout);\r
463 > -    else\r
464 > -     fputs (format->results_end, stdout);\r
465 > +    format->end (format);\r
466 >  \r
467 >      return 0;\r
468 >  }\r
469 >  \r
470 >  static int\r
471 >  do_search_tags (notmuch_database_t *notmuch,\r
472 > -             const search_format_t *format,\r
473 > +             sprinter_t *format,\r
474 >               notmuch_query_t *query)\r
475 >  {\r
476 >      notmuch_messages_t *messages = NULL;\r
477 >      notmuch_tags_t *tags;\r
478 >      const char *tag;\r
479 > -    int first_tag = 1;\r
480 >  \r
481 >      /* should the following only special case if no excluded terms\r
482 >       * specified? */\r
483 > @@ -387,7 +211,7 @@ do_search_tags (notmuch_database_t *notmuch,\r
484 >      if (tags == NULL)\r
485 >       return 1;\r
486 >  \r
487 > -    fputs (format->results_start, stdout);\r
488 > +    format->begin_list (format);\r
489 >  \r
490 >      for (;\r
491 >        notmuch_tags_valid (tags);\r
492 > @@ -395,12 +219,9 @@ do_search_tags (notmuch_database_t *notmuch,\r
493 >      {\r
494 >       tag = notmuch_tags_get (tags);\r
495 >  \r
496 > -     if (! first_tag)\r
497 > -         fputs (format->item_sep, stdout);\r
498 > +     format->string (format, tag);\r
499 > +     format->separator (format);\r
500 >  \r
501 > -     format->item_id (tags, "", tag);\r
502 > -\r
503 > -     first_tag = 0;\r
504 >      }\r
505 >  \r
506 >      notmuch_tags_destroy (tags);\r
507 > @@ -408,10 +229,7 @@ do_search_tags (notmuch_database_t *notmuch,\r
508 >      if (messages)\r
509 >       notmuch_messages_destroy (messages);\r
510 >  \r
511 > -    if (first_tag)\r
512 > -     fputs (format->results_null, stdout);\r
513 > -    else\r
514 > -     fputs (format->results_end, stdout);\r
515 > +    format->end (format);\r
516 >  \r
517 >      return 0;\r
518 >  }\r
519 > @@ -430,7 +248,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
520 >      notmuch_query_t *query;\r
521 >      char *query_str;\r
522 >      notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;\r
523 > -    const search_format_t *format = &format_text;\r
524 > +    sprinter_t *format = NULL;\r
525 >      int opt_index, ret;\r
526 >      output_t output = OUTPUT_SUMMARY;\r
527 >      int offset = 0;\r
528 > @@ -475,10 +293,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
529 >  \r
530 >      switch (format_sel) {\r
531 >      case NOTMUCH_FORMAT_TEXT:\r
532 > -     format = &format_text;\r
533 > +     format = sprinter_text_search_create (ctx, stdout);\r
534 >       break;\r
535 >      case NOTMUCH_FORMAT_JSON:\r
536 > -     format = &format_json;\r
537 > +     format = sprinter_json_create (ctx, stdout);\r
538 >       break;\r
539 >      }\r
540 >  \r
541 > @@ -546,5 +364,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
542 >      notmuch_query_destroy (query);\r
543 >      notmuch_database_destroy (notmuch);\r
544 >  \r
545 > +    talloc_free (format);\r
546 > +\r
547 >      return ret;\r
548 >  }\r
549 > diff --git a/test/json b/test/json\r
550 > index 6439788..f0ebf08 100755\r
551 > --- a/test/json\r
552 > +++ b/test/json\r
553 > @@ -10,14 +10,7 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e\r
554 >  test_begin_subtest "Search message: json"\r
555 >  add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""\r
556 >  output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)\r
557 \r
558 If you pipe this through notmuch_json_show_sanitize, it'll make the\r
559 test output much cleaner and closer to the original output (probably\r
560 not exactly the same, unfortunately).\r
561 \r
562 > -test_expect_equal "$output" "[{\"thread\": \"XXX\",\r
563 > -\"timestamp\": 946728000,\r
564 > -\"date_relative\": \"2000-01-01\",\r
565 > -\"matched\": 1,\r
566 > -\"total\": 1,\r
567 > -\"authors\": \"Notmuch Test Suite\",\r
568 > -\"subject\": \"json-search-subject\",\r
569 > -\"tags\": [\"inbox\", \"unread\"]}]"\r
570 > +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
571 >  \r
572 >  test_begin_subtest "Show message: json, utf-8"\r
573 >  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
574 > @@ -40,13 +33,6 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":\r
575 >  test_begin_subtest "Search message: json, utf-8"\r
576 >  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
577 >  output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)\r
578 \r
579 Same here.\r
580 \r
581 > -test_expect_equal "$output" "[{\"thread\": \"XXX\",\r
582 > -\"timestamp\": 946728000,\r
583 > -\"date_relative\": \"2000-01-01\",\r
584 > -\"matched\": 1,\r
585 > -\"total\": 1,\r
586 > -\"authors\": \"Notmuch Test Suite\",\r
587 > -\"subject\": \"json-search-utf8-body-sübjéct\",\r
588 > -\"tags\": [\"inbox\", \"unread\"]}]"\r
589 > +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
590 >  \r
591 >  test_done\r