Re: [feature request] emacs: use `notmuch insert` for FCC
[notmuch-archives.git] / 83 / fcbf6403aa78196034c00a1fb8fc6bc7e1fb74
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 68BFD431FAF\r
6         for <notmuch@notmuchmail.org>; Thu, 12 Jul 2012 17:02:42 -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 O-SDe8Ki+tco for <notmuch@notmuchmail.org>;\r
16         Thu, 12 Jul 2012 17:02:39 -0700 (PDT)\r
17 Received: from dmz-mailsec-scanner-2.mit.edu (DMZ-MAILSEC-SCANNER-2.MIT.EDU\r
18         [18.9.25.13])\r
19         by olra.theworths.org (Postfix) with ESMTP id B3DEE431FAE\r
20         for <notmuch@notmuchmail.org>; Thu, 12 Jul 2012 17:02:38 -0700 (PDT)\r
21 X-AuditID: 1209190d-b7fd56d000000933-78-4fff659e682e\r
22 Received: from mailhub-auth-2.mit.edu ( [18.7.62.36])\r
23         by dmz-mailsec-scanner-2.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id C7.25.02355.E956FFF4; Thu, 12 Jul 2012 20:02:38 -0400 (EDT)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-2.mit.edu (8.13.8/8.9.2) with ESMTP id q6D02bsI005845; \r
27         Thu, 12 Jul 2012 20:02:37 -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 q6D02ZQW000240\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Thu, 12 Jul 2012 20:02:36 -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 1SpTL8-00056E-UV; Thu, 12 Jul 2012 20:02:35 -0400\r
37 Date: Thu, 12 Jul 2012 20:02:34 -0400\r
38 From: Austin Clements <amdragon@MIT.EDU>\r
39 To: craven@gmx.net\r
40 Subject: Re: [PATCH v4 3/3] Use the structured format printer for JSON in\r
41         notmuch search.\r
42 Message-ID: <20120713000234.GK7332@mit.edu>\r
43 References: <87d34hsdx8.fsf@awakening.csail.mit.edu>\r
44         <1342079004-5300-1-git-send-email-craven@gmx.net>\r
45         <1342079004-5300-4-git-send-email-craven@gmx.net>\r
46 MIME-Version: 1.0\r
47 Content-Type: text/plain; charset=iso-8859-1\r
48 Content-Disposition: inline\r
49 Content-Transfer-Encoding: 8bit\r
50 In-Reply-To: <1342079004-5300-4-git-send-email-craven@gmx.net>\r
51 User-Agent: Mutt/1.5.21 (2010-09-15)\r
52 X-Brightmail-Tracker:\r
53  H4sIAAAAAAAAA+NgFprLKsWRmVeSWpSXmKPExsUixG6nojsv9b+/wbQXrBZ7G9oZLa7fnMns\r
54         wOSxeNN+No9nq24xBzBFcdmkpOZklqUW6dslcGXMX3mGtWDLJ8aKS99uszQwth1m7GLk5JAQ\r
55         MJE4MvUMC4QtJnHh3no2EFtIYB+jxJ1Ddl2MXED2BkaJnwuXMEMkTjJJ/NxvBJFYwiix+OIy\r
56         sA4WAVWJN6f3gxWxCWhIbNu/HGyDiICQxKQvr8A2MAtIS3z73cwEYgsLREtMmHYZzOYV0Jb4\r
57         tfIbK8TQOYwS3QceMkMkBCVOznwC1awjsXPrHaBlHGCDlv/jgAjLSzRvnQ1WzilgJzHn0kaw\r
58         clEBFYkpJ7exTWAUnoVk0iwkk2YhTJqFZNICRpZVjLIpuVW6uYmZOcWpybrFyYl5ealFukZ6\r
59         uZkleqkppZsYQbHAKcm7g/HdQaVDjAIcjEo8vL9i//sLsSaWFVfmHmKU5GBSEuWNSQIK8SXl\r
60         p1RmJBZnxBeV5qQWH2KU4GBWEuFdZw+U401JrKxKLcqHSUlzsCiJ815JuekvJJCeWJKanZpa\r
61         kFoEk5Xh4FCS4N2eAtQoWJSanlqRlplTgpBm4uAEGc4DNPwWSA1vcUFibnFmOkT+FKOilDjv\r
62         EpCEAEgiozQPrheWql4xigO9Isw7H6SKB5jm4LpfAQ1mAho86+c/kMEliQgpqQZGh5gAlkOX\r
63         T7TPm/7u37l9fHzcHg9Xu+yccq7srOymXtHaJZ/aFE+c//7FWzdSgF0zUn5lc8CkqHcnOLdM\r
64         N5bqUdy254+0vm6DtNiv2zdFRBWPqxnvmhk7sdk+g++mxJO/8hNfWKgYvF/3f+PDR7Xr0rz/\r
65         f9ksWjRhZVmDpPOXF2VMe/w1Guo2K7EUZyQaajEXFScCABrTpOcwAwAA\r
66 Cc: notmuch@notmuchmail.org\r
67 X-BeenThere: notmuch@notmuchmail.org\r
68 X-Mailman-Version: 2.1.13\r
69 Precedence: list\r
70 List-Id: "Use and development of the notmuch mail system."\r
71         <notmuch.notmuchmail.org>\r
72 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
73         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
74 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
75 List-Post: <mailto:notmuch@notmuchmail.org>\r
76 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
77 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
78         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
79 X-List-Received-Date: Fri, 13 Jul 2012 00:02:42 -0000\r
80 \r
81 This is fantastic.  It simplifies the code a lot, and I think it opens\r
82 up opportunities to simplify it even further.\r
83 \r
84 Detailed comments are below, but first one general comment.  For the\r
85 text format, I wonder if most of the special case code would go away\r
86 with a stub sprinter that did nothing for most operations and for\r
87 string printed the string followed by a newline (or maybe the newline\r
88 would be printed by the "frame" method or whatever you end up calling\r
89 it).  I believe this would unify all of the code in do_search_tags and\r
90 do_search_files between the two formats.  For do_search_threads,\r
91 you'll still need some special-casing to format the summary line, but\r
92 I think it would unify all of the framing code.  (If this does work\r
93 out, some of my comments below will be irrelevant.)\r
94 \r
95 Quoth craven@gmx.net on Jul 12 at  9:43 am:\r
96 > This patch switches from the current ad-hoc printer to the structured\r
97 > output formatter in sprinter.h.\r
98\r
99 > It removes search_format_t, replaces it by sprinter_t and inlines the\r
100 > text printer where necessary.\r
101\r
102 > The tests are changed (only whitespaces and regular expressions) in\r
103 > order to make them PASS for the new structured output formatter.\r
104 > ---\r
105 >  notmuch-search.c   | 349 ++++++++++++++++++++++-------------------------------\r
106 >  test/json          |  20 +--\r
107 >  test/search-output | 270 +++++++++++++++++++++--------------------\r
108 >  3 files changed, 288 insertions(+), 351 deletions(-)\r
109\r
110 > diff --git a/notmuch-search.c b/notmuch-search.c\r
111 > index 3be296d..b853f5f 100644\r
112 > --- a/notmuch-search.c\r
113 > +++ b/notmuch-search.c\r
114 > @@ -19,6 +19,7 @@\r
115 >   */\r
116 >  \r
117 >  #include "notmuch-client.h"\r
118 > +#include "sprinter.h"\r
119 >  \r
120 >  typedef enum {\r
121 >      OUTPUT_SUMMARY,\r
122 > @@ -28,91 +29,9 @@ typedef enum {\r
123 >      OUTPUT_TAGS\r
124 >  } output_t;\r
125 >  \r
126 > -typedef struct search_format {\r
127 > -    const char *results_start;\r
128 > -    const char *item_start;\r
129 > -    void (*item_id) (const void *ctx,\r
130 > -                  const char *item_type,\r
131 > -                  const char *item_id);\r
132 > -    void (*thread_summary) (const void *ctx,\r
133 > -                         const char *thread_id,\r
134 > -                         const time_t date,\r
135 > -                         const int matched,\r
136 > -                         const int total,\r
137 > -                         const char *authors,\r
138 > -                         const char *subject);\r
139 > -    const char *tag_start;\r
140 > -    const char *tag;\r
141 > -    const char *tag_sep;\r
142 > -    const char *tag_end;\r
143 > -    const char *item_sep;\r
144 > -    const char *item_end;\r
145 > -    const char *results_end;\r
146 > -    const char *results_null;\r
147 > -} search_format_t;\r
148 > -\r
149 > -static void\r
150 > -format_item_id_text (const void *ctx,\r
151 > -                  const char *item_type,\r
152 > -                  const char *item_id);\r
153 > -\r
154 > -static void\r
155 > -format_thread_text (const void *ctx,\r
156 > -                 const char *thread_id,\r
157 > -                 const time_t date,\r
158 > -                 const int matched,\r
159 > -                 const int total,\r
160 > -                 const char *authors,\r
161 > -                 const char *subject);\r
162 > -static const search_format_t format_text = {\r
163 > -    "",\r
164 > -     "",\r
165 > -         format_item_id_text,\r
166 > -         format_thread_text,\r
167 > -         " (",\r
168 > -             "%s", " ",\r
169 > -         ")", "\n",\r
170 > -     "",\r
171 > -    "\n",\r
172 > -    "",\r
173 > -};\r
174 > -\r
175 > -static void\r
176 > -format_item_id_json (const void *ctx,\r
177 > -                  const char *item_type,\r
178 > -                  const char *item_id);\r
179 > -\r
180 > -static void\r
181 > -format_thread_json (const void *ctx,\r
182 > -                 const char *thread_id,\r
183 > -                 const time_t date,\r
184 > -                 const int matched,\r
185 > -                 const int total,\r
186 > -                 const char *authors,\r
187 > -                 const char *subject);\r
188 > -\r
189 > -/* Any changes to the JSON format should be reflected in the file\r
190 > - * devel/schemata. */\r
191 > -static const search_format_t format_json = {\r
192 > -    "[",\r
193 > -     "{",\r
194 > -         format_item_id_json,\r
195 > -         format_thread_json,\r
196 > -         "\"tags\": [",\r
197 > -             "\"%s\"", ", ",\r
198 > -         "]", ",\n",\r
199 > -     "}",\r
200 > -    "]\n",\r
201 > -    "]\n",\r
202 > -};\r
203 > -\r
204 > -static void\r
205 > -format_item_id_text (unused (const void *ctx),\r
206 > -                  const char *item_type,\r
207 > -                  const char *item_id)\r
208 > -{\r
209 > -    printf ("%s%s", item_type, item_id);\r
210 > -}\r
211 > +static const char * text_item_sep = "\n";\r
212 > +static const char * text_results_null = "";\r
213 > +static const char * text_results_end = "\n";\r
214 \r
215 Given that you're special-casing the text format anyway, I think it's\r
216 actually more readable if you hard-code these in the appropriate\r
217 places below.\r
218 \r
219 >  \r
220 >  static char *\r
221 >  sanitize_string (const void *ctx, const char *str)\r
222 > @@ -131,72 +50,8 @@ sanitize_string (const void *ctx, const char *str)\r
223 >      return out;\r
224 >  }\r
225 >  \r
226 > -static void\r
227 > -format_thread_text (const void *ctx,\r
228 > -                 const char *thread_id,\r
229 > -                 const time_t date,\r
230 > -                 const int matched,\r
231 > -                 const int total,\r
232 > -                 const char *authors,\r
233 > -                 const char *subject)\r
234 > -{\r
235 > -    void *ctx_quote = talloc_new (ctx);\r
236 > -\r
237 > -    printf ("thread:%s %12s [%d/%d] %s; %s",\r
238 > -         thread_id,\r
239 > -         notmuch_time_relative_date (ctx, date),\r
240 > -         matched,\r
241 > -         total,\r
242 > -         sanitize_string (ctx_quote, authors),\r
243 > -         sanitize_string (ctx_quote, subject));\r
244 > -\r
245 > -    talloc_free (ctx_quote);\r
246 > -}\r
247 > -\r
248 > -static void\r
249 > -format_item_id_json (const void *ctx,\r
250 > -                  unused (const char *item_type),\r
251 > -                  const char *item_id)\r
252 > -{\r
253 > -    void *ctx_quote = talloc_new (ctx);\r
254 > -\r
255 > -    printf ("%s", json_quote_str (ctx_quote, item_id));\r
256 > -\r
257 > -    talloc_free (ctx_quote);\r
258 > -    \r
259 > -}\r
260 > -\r
261 > -static void\r
262 > -format_thread_json (const void *ctx,\r
263 > -                 const char *thread_id,\r
264 > -                 const time_t date,\r
265 > -                 const int matched,\r
266 > -                 const int total,\r
267 > -                 const char *authors,\r
268 > -                 const char *subject)\r
269 > -{\r
270 > -    void *ctx_quote = talloc_new (ctx);\r
271 > -\r
272 > -    printf ("\"thread\": %s,\n"\r
273 > -         "\"timestamp\": %ld,\n"\r
274 > -         "\"date_relative\": \"%s\",\n"\r
275 > -         "\"matched\": %d,\n"\r
276 > -         "\"total\": %d,\n"\r
277 > -         "\"authors\": %s,\n"\r
278 > -         "\"subject\": %s,\n",\r
279 > -         json_quote_str (ctx_quote, thread_id),\r
280 > -         date,\r
281 > -         notmuch_time_relative_date (ctx, date),\r
282 > -         matched,\r
283 > -         total,\r
284 > -         json_quote_str (ctx_quote, authors),\r
285 > -         json_quote_str (ctx_quote, subject));\r
286 > -\r
287 > -    talloc_free (ctx_quote);\r
288 > -}\r
289 > -\r
290 >  static int\r
291 > -do_search_threads (const search_format_t *format,\r
292 > +do_search_threads (sprinter_t *format,\r
293 >                  notmuch_query_t *query,\r
294 >                  notmuch_sort_t sort,\r
295 >                  output_t output,\r
296 > @@ -220,7 +75,9 @@ do_search_threads (const search_format_t *format,\r
297 >      if (threads == NULL)\r
298 >       return 1;\r
299 >  \r
300 > -    fputs (format->results_start, stdout);\r
301 > +    if (format != sprinter_text) {\r
302 > +     format->begin_list (format);\r
303 > +    }\r
304 >  \r
305 >      for (i = 0;\r
306 >        notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);\r
307 > @@ -235,43 +92,96 @@ do_search_threads (const search_format_t *format,\r
308 >           continue;\r
309 >       }\r
310 >  \r
311 > -     if (! first_thread)\r
312 > -         fputs (format->item_sep, stdout);\r
313 > +     if (format == sprinter_text && ! first_thread)\r
314 > +         fputs (text_item_sep, stdout);\r
315 \r
316 I think you can drop this (and the first_thread variable) if you print\r
317 ")\n" instead of ")" down below.  This roundabout first_thread stuff\r
318 was necessary to support the JSON format because it uses separators\r
319 between results; however, the text format is much simpler because it\r
320 just has the terminating newline after each result.  Hence, you can\r
321 just bake printing the newline in with printing the result and you\r
322 never have to worry about whether it's the first result of if you\r
323 didn't print any results.\r
324 \r
325 >  \r
326 >       if (output == OUTPUT_THREADS) {\r
327 > -         format->item_id (thread, "thread:",\r
328 > -                          notmuch_thread_get_thread_id (thread));\r
329 > +         const char *thread_id = notmuch_thread_get_thread_id (thread);\r
330 > +         if (format == sprinter_text)\r
331 > +             printf ("thread:%s", thread_id);\r
332 > +         else {\r
333 > +             format->string (format, thread_id);\r
334 > +             format->frame (format);\r
335 > +         }\r
336 > +\r
337 >       } else { /* output == OUTPUT_SUMMARY */\r
338 > -         fputs (format->item_start, stdout);\r
339 > +         const char *authors = notmuch_thread_get_authors (thread);\r
340 > +         const char *subject = notmuch_thread_get_subject (thread);\r
341 > +         const char *thread_id = notmuch_thread_get_thread_id (thread);\r
342 > +         int matched = notmuch_thread_get_matched_messages (thread);\r
343 > +         int total = notmuch_thread_get_total_messages (thread);\r
344 > +         const char *relative_date = NULL;\r
345 > +\r
346 > +         if (format != sprinter_text)\r
347 > +             format->begin_map (format);\r
348 > +\r
349 \r
350 Extra blank line.\r
351 \r
352 >  \r
353 >           if (sort == NOTMUCH_SORT_OLDEST_FIRST)\r
354 >               date = notmuch_thread_get_oldest_date (thread);\r
355 >           else\r
356 >               date = notmuch_thread_get_newest_date (thread);\r
357 >  \r
358 > -         format->thread_summary (thread,\r
359 > -                                 notmuch_thread_get_thread_id (thread),\r
360 > -                                 date,\r
361 > -                                 notmuch_thread_get_matched_messages (thread),\r
362 > -                                 notmuch_thread_get_total_messages (thread),\r
363 > -                                 notmuch_thread_get_authors (thread),\r
364 > -                                 notmuch_thread_get_subject (thread));\r
365 > +         void *ctx_quote = talloc_new (thread);\r
366 > +         relative_date =\r
367 > +             notmuch_time_relative_date (ctx_quote, date);\r
368 > +\r
369 > +         if (format == sprinter_text) {\r
370 > +             printf ("thread:%s %12s [%d/%d] %s; %s",\r
371 > +                     thread_id,\r
372 > +                     relative_date,\r
373 > +                     matched,\r
374 > +                     total,\r
375 > +                     sanitize_string (ctx_quote, authors),\r
376 > +                     sanitize_string (ctx_quote, subject));\r
377 > +         } else {\r
378 > +             format->map_key (format, "thread");\r
379 > +             format->string (format, thread_id);\r
380 > +             format->map_key (format, "timestamp");\r
381 > +             format->integer (format, date);\r
382 > +             format->map_key (format, "date_relative");\r
383 > +             format->string (format, relative_date);\r
384 > +             format->map_key (format, "matched");\r
385 > +             format->integer (format, matched);\r
386 > +             format->map_key (format, "total");\r
387 > +             format->integer (format, total);\r
388 > +             format->map_key (format, "authors");\r
389 > +             format->string (format, authors);\r
390 > +             format->map_key (format, "subject");\r
391 > +             format->string (format, subject);\r
392 > +         }\r
393 > +\r
394 > +         talloc_free (ctx_quote);\r
395 >  \r
396 > -         fputs (format->tag_start, stdout);\r
397 > +         if (format == sprinter_text) {\r
398 > +             fputs (" (", stdout);\r
399 > +         } else {\r
400 > +             format->map_key (format, "tags");\r
401 > +             format->begin_list (format);\r
402 > +         }\r
403 >  \r
404 >           for (tags = notmuch_thread_get_tags (thread);\r
405 >                notmuch_tags_valid (tags);\r
406 >                notmuch_tags_move_to_next (tags))\r
407 >           {\r
408 > -             if (! first_tag)\r
409 > -                 fputs (format->tag_sep, stdout);\r
410 > -             printf (format->tag, notmuch_tags_get (tags));\r
411 > +             const char *tag = notmuch_tags_get (tags);\r
412 > +             if (format == sprinter_text) {\r
413 > +                 if (! first_tag)\r
414 > +                     fputs (" ", stdout);\r
415 > +                 fputs (tag, stdout);\r
416 > +             } else {\r
417 > +                 format->string (format, tag);\r
418 > +             }\r
419 > +\r
420 >               first_tag = 0;\r
421 >           }\r
422 >  \r
423 > -         fputs (format->tag_end, stdout);\r
424 > -\r
425 > -         fputs (format->item_end, stdout);\r
426 > +         if (format == sprinter_text) {\r
427 > +             fputs (")", stdout);\r
428 > +         } else {\r
429 > +             format->end (format);\r
430 > +             format->end (format);\r
431 > +             format->frame (format);\r
432 > +         }\r
433 >       }\r
434 >  \r
435 >       first_thread = 0;\r
436 > @@ -279,16 +189,20 @@ do_search_threads (const search_format_t *format,\r
437 >       notmuch_thread_destroy (thread);\r
438 >      }\r
439 >  \r
440 > -    if (first_thread)\r
441 > -     fputs (format->results_null, stdout);\r
442 > -    else\r
443 > -     fputs (format->results_end, stdout);\r
444 > +    if (format == sprinter_text)\r
445 > +     if (first_thread)\r
446 > +         fputs (text_results_null, stdout);\r
447 > +     else\r
448 > +         fputs (text_results_end, stdout);\r
449 \r
450 You can drop this, too, if you print ")\n" instead of ")" above.\r
451 \r
452 > +    else {\r
453 > +     format->end (format);\r
454 > +    }\r
455 >  \r
456 >      return 0;\r
457 >  }\r
458 >  \r
459 >  static int\r
460 > -do_search_messages (const search_format_t *format,\r
461 > +do_search_messages (sprinter_t *format,\r
462 >                   notmuch_query_t *query,\r
463 >                   output_t output,\r
464 >                   int offset,\r
465 > @@ -310,7 +224,8 @@ do_search_messages (const search_format_t *format,\r
466 >      if (messages == NULL)\r
467 >       return 1;\r
468 >  \r
469 > -    fputs (format->results_start, stdout);\r
470 > +    if (format != sprinter_text)\r
471 > +     format->begin_list (format);\r
472 >  \r
473 >      for (i = 0;\r
474 >        notmuch_messages_valid (messages) && (limit < 0 || i < offset + limit);\r
475 > @@ -328,23 +243,36 @@ do_search_messages (const search_format_t *format,\r
476 >                notmuch_filenames_valid (filenames);\r
477 >                notmuch_filenames_move_to_next (filenames))\r
478 >           {\r
479 > -             if (! first_message)\r
480 > -                 fputs (format->item_sep, stdout);\r
481 > +             const char *filenames_str = notmuch_filenames_get (filenames);\r
482 > +\r
483 > +             if (format == sprinter_text && ! first_message)\r
484 > +                 fputs (text_item_sep, stdout);\r
485 \r
486 Likewise, you can remove this, the first_message logic for\r
487 OUTPUT_MESSAGES, and the first_message logic at the end of this\r
488 function if you print a newline after filenames_str and message_id.\r
489 \r
490 >  \r
491 > -             format->item_id (message, "",\r
492 > -                              notmuch_filenames_get (filenames));\r
493 > +             if (format == sprinter_text)\r
494 > +                 fputs (filenames_str, stdout);\r
495 > +             else {\r
496 > +                 format->string (format, filenames_str);\r
497 > +                 format->frame (format);\r
498 > +             }\r
499 >  \r
500 >               first_message = 0;\r
501 >           }\r
502 > -         \r
503 > -         notmuch_filenames_destroy( filenames );\r
504 > +\r
505 > +         notmuch_filenames_destroy (filenames);\r
506 \r
507 No need to reformat this.\r
508 \r
509 >  \r
510 >       } else { /* output == OUTPUT_MESSAGES */\r
511 > -         if (! first_message)\r
512 > -             fputs (format->item_sep, stdout);\r
513 > +         const char *message_id = notmuch_message_get_message_id (message);\r
514 > +\r
515 > +         if (format == sprinter_text && ! first_message)\r
516 > +             fputs (text_item_sep, stdout);\r
517 > +\r
518 > +         if (format == sprinter_text)\r
519 > +             printf ("id:%s", message_id);\r
520 > +         else {\r
521 > +             format->string (format, message_id);\r
522 > +             format->frame (format);\r
523 > +         }\r
524 >  \r
525 > -         format->item_id (message, "id:",\r
526 > -                          notmuch_message_get_message_id (message));\r
527 >           first_message = 0;\r
528 >       }\r
529 >  \r
530 > @@ -353,17 +281,21 @@ do_search_messages (const search_format_t *format,\r
531 >  \r
532 >      notmuch_messages_destroy (messages);\r
533 >  \r
534 > -    if (first_message)\r
535 > -     fputs (format->results_null, stdout);\r
536 > -    else\r
537 > -     fputs (format->results_end, stdout);\r
538 > +    if (format == sprinter_text)\r
539 > +     if (first_message)\r
540 > +         fputs (text_results_null, stdout);\r
541 > +     else\r
542 > +         fputs (text_results_end, stdout);\r
543 > +    else {\r
544 > +     format->end (format);\r
545 > +    }\r
546 >  \r
547 >      return 0;\r
548 >  }\r
549 >  \r
550 >  static int\r
551 >  do_search_tags (notmuch_database_t *notmuch,\r
552 > -             const search_format_t *format,\r
553 > +             sprinter_t *format,\r
554 >               notmuch_query_t *query)\r
555 >  {\r
556 >      notmuch_messages_t *messages = NULL;\r
557 > @@ -387,7 +319,8 @@ do_search_tags (notmuch_database_t *notmuch,\r
558 >      if (tags == NULL)\r
559 >       return 1;\r
560 >  \r
561 > -    fputs (format->results_start, stdout);\r
562 > +    if (format != sprinter_text)\r
563 > +     format->begin_list (format);\r
564 >  \r
565 >      for (;\r
566 >        notmuch_tags_valid (tags);\r
567 > @@ -395,10 +328,15 @@ do_search_tags (notmuch_database_t *notmuch,\r
568 >      {\r
569 >       tag = notmuch_tags_get (tags);\r
570 >  \r
571 > -     if (! first_tag)\r
572 > -         fputs (format->item_sep, stdout);\r
573 > +     if (format == sprinter_text && ! first_tag)\r
574 > +         fputs (text_item_sep, stdout);\r
575 \r
576 Same thing about dropping the first_tag logic in this function if you\r
577 print a newline after tag below.\r
578 \r
579 >  \r
580 > -     format->item_id (tags, "", tag);\r
581 > +     if (format == sprinter_text)\r
582 > +         fputs (tag, stdout);\r
583 > +     else {\r
584 > +         format->string (format, tag);\r
585 > +         format->frame (format);\r
586 > +     }\r
587 >  \r
588 >       first_tag = 0;\r
589 >      }\r
590 > @@ -408,10 +346,14 @@ do_search_tags (notmuch_database_t *notmuch,\r
591 >      if (messages)\r
592 >       notmuch_messages_destroy (messages);\r
593 >  \r
594 > -    if (first_tag)\r
595 > -     fputs (format->results_null, stdout);\r
596 > -    else\r
597 > -     fputs (format->results_end, stdout);\r
598 > +    if (format == sprinter_text)\r
599 > +     if (first_tag)\r
600 > +         fputs (text_results_null, stdout);\r
601 > +     else\r
602 > +         fputs (text_results_end, stdout);\r
603 > +    else {\r
604 > +     format->end (format);\r
605 > +    }\r
606 >  \r
607 >      return 0;\r
608 >  }\r
609 > @@ -430,7 +372,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
610 >      notmuch_query_t *query;\r
611 >      char *query_str;\r
612 >      notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;\r
613 > -    const search_format_t *format = &format_text;\r
614 > +    sprinter_t *format = NULL; /* the default output is text */\r
615 >      int opt_index, ret;\r
616 >      output_t output = OUTPUT_SUMMARY;\r
617 >      int offset = 0;\r
618 > @@ -475,10 +417,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
619 >  \r
620 >      switch (format_sel) {\r
621 >      case NOTMUCH_FORMAT_TEXT:\r
622 > -     format = &format_text;\r
623 > +     format = NULL;\r
624 >       break;\r
625 >      case NOTMUCH_FORMAT_JSON:\r
626 > -     format = &format_json;\r
627 > +     format = sprinter_json_new (ctx, stdout);\r
628 >       break;\r
629 >      }\r
630 >  \r
631 > @@ -546,5 +488,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
632 >      notmuch_query_destroy (query);\r
633 >      notmuch_database_destroy (notmuch);\r
634 >  \r
635 > +    if (format != sprinter_text)\r
636 > +     talloc_free(format);\r
637 \r
638 Missing space before argument list.\r
639 \r
640 > +\r
641 >      return ret;\r
642 >  }\r
643 > diff --git a/test/json b/test/json\r
644 > index 6439788..88b8a6d 100755\r
645 > --- a/test/json\r
646 > +++ b/test/json\r
647 > @@ -10,14 +10,8 @@ test_expect_equal "$output" "[[[{\"id\": \"${gen_msg_id}\", \"match\": true, \"e\r
648 >  test_begin_subtest "Search message: json"\r
649 >  add_message "[subject]=\"json-search-subject\"" "[date]=\"Sat, 01 Jan 2000 12:00:00 -0000\"" "[body]=\"json-search-message\""\r
650 >  output=$(notmuch search --format=json "json-search-message" | notmuch_search_sanitize)\r
651 \r
652 If you additionally pipe this through notmuch_json_show_sanitize (or\r
653 maybe define a similar function for search), then the output will be\r
654 much closer to the output currently in the test.\r
655 \r
656 > -test_expect_equal "$output" "[{\"thread\": \"XXX\",\r
657 > -\"timestamp\": 946728000,\r
658 > -\"date_relative\": \"2000-01-01\",\r
659 > -\"matched\": 1,\r
660 > -\"total\": 1,\r
661 > -\"authors\": \"Notmuch Test Suite\",\r
662 > -\"subject\": \"json-search-subject\",\r
663 > -\"tags\": [\"inbox\", \"unread\"]}]"\r
664 > +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
665 > +]"\r
666 >  \r
667 >  test_begin_subtest "Show message: json, utf-8"\r
668 >  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
669 > @@ -40,13 +34,7 @@ test_expect_equal "$output" "[[[{\"id\": \"$id\", \"match\": true, \"excluded\":\r
670 >  test_begin_subtest "Search message: json, utf-8"\r
671 >  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
672 >  output=$(notmuch search --format=json "jsön-search-méssage" | notmuch_search_sanitize)\r
673 \r
674 Same here.\r
675 \r
676 > -test_expect_equal "$output" "[{\"thread\": \"XXX\",\r
677 > -\"timestamp\": 946728000,\r
678 > -\"date_relative\": \"2000-01-01\",\r
679 > -\"matched\": 1,\r
680 > -\"total\": 1,\r
681 > -\"authors\": \"Notmuch Test Suite\",\r
682 > -\"subject\": \"json-search-utf8-body-sübjéct\",\r
683 > -\"tags\": [\"inbox\", \"unread\"]}]"\r
684 > +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
685 > +]"\r
686 >  \r
687 >  test_done\r
688 > diff --git a/test/search-output b/test/search-output\r
689 > index 8b57a43..f2650f7 100755\r
690 > --- a/test/search-output\r
691 > +++ b/test/search-output\r
692 > @@ -37,30 +37,31 @@ test_expect_equal_file OUTPUT EXPECTED\r
693 >  test_begin_subtest "--output=threads --format=json"\r
694 >  notmuch search --format=json --output=threads '*' | sed -e s/\".*\"/\"THREADID\"/ >OUTPUT\r
695 >  cat <<EOF >EXPECTED\r
696 > -["THREADID",\r
697 > -"THREADID",\r
698 > -"THREADID",\r
699 > -"THREADID",\r
700 > -"THREADID",\r
701 > -"THREADID",\r
702 > -"THREADID",\r
703 > -"THREADID",\r
704 > -"THREADID",\r
705 > -"THREADID",\r
706 > -"THREADID",\r
707 > -"THREADID",\r
708 > -"THREADID",\r
709 > -"THREADID",\r
710 > -"THREADID",\r
711 > -"THREADID",\r
712 > -"THREADID",\r
713 > -"THREADID",\r
714 > -"THREADID",\r
715 > -"THREADID",\r
716 > -"THREADID",\r
717 > -"THREADID",\r
718 > -"THREADID",\r
719 > -"THREADID"]\r
720 > +["THREADID"\r
721 > +, "THREADID"\r
722 > +, "THREADID"\r
723 > +, "THREADID"\r
724 > +, "THREADID"\r
725 > +, "THREADID"\r
726 > +, "THREADID"\r
727 > +, "THREADID"\r
728 > +, "THREADID"\r
729 > +, "THREADID"\r
730 > +, "THREADID"\r
731 > +, "THREADID"\r
732 > +, "THREADID"\r
733 > +, "THREADID"\r
734 > +, "THREADID"\r
735 > +, "THREADID"\r
736 > +, "THREADID"\r
737 > +, "THREADID"\r
738 > +, "THREADID"\r
739 > +, "THREADID"\r
740 > +, "THREADID"\r
741 > +, "THREADID"\r
742 > +, "THREADID"\r
743 > +, "THREADID"\r
744 > +]\r
745 \r
746 Hmm.  It would be nice if json_frame printed this in the way people\r
747 usually format JSON and the test currently expects.  Doing this isn't\r
748 entirely straightforward because the caller could call frame and then\r
749 immediately call end, so you can't just print ",\n"...\r
750 \r
751 You could replace json_state.first with\r
752   /* The separator to print before the next value. */\r
753   const char *sep;\r
754 json_begin_value would fputs sep and set it to ", ",\r
755 json_begin_aggregate would set it to "", and json_map_key would set it\r
756 to ": " and not fputs(": ", spj->stream) itself.  json_frame could\r
757 then be something like\r
758 \r
759 static void\r
760 json_frame(struct sprinter *sp)\r
761 {\r
762     struct json_state *state = ((struct sprinter_json*)sp)->state;\r
763     if (!state)\r
764       return;\r
765     if (state->sep[0] == ',')\r
766       state->sep = ",\n";\r
767     else if (state->sep[0] == ':')\r
768       state->sep = ":\n";\r
769 }\r
770 \r
771 I think that would work.\r
772 \r
773 >  EOF\r
774 >  test_expect_equal_file OUTPUT EXPECTED\r
775 >  \r
776 > @@ -125,58 +126,59 @@ test_expect_equal_file OUTPUT EXPECTED\r
777 >  test_begin_subtest "--output=messages --format=json"\r
778 >  notmuch search --format=json --output=messages '*' >OUTPUT\r
779 >  cat <<EOF >EXPECTED\r
780 > -["4EFC743A.3060609@april.org",\r
781 > -"877h1wv7mg.fsf@inf-8657.int-evry.fr",\r
782 > -"1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk",\r
783 > -"877htoqdbo.fsf@yoom.home.cworth.org",\r
784 > -"878we4qdqf.fsf@yoom.home.cworth.org",\r
785 > -"87aaykqe24.fsf@yoom.home.cworth.org",\r
786 > -"87bpj0qeng.fsf@yoom.home.cworth.org",\r
787 > -"87fx8cqf8v.fsf@yoom.home.cworth.org",\r
788 > -"87hbssqfix.fsf@yoom.home.cworth.org",\r
789 > -"87iqd8qgiz.fsf@yoom.home.cworth.org",\r
790 > -"87k4xoqgnl.fsf@yoom.home.cworth.org",\r
791 > -"87ocn0qh6d.fsf@yoom.home.cworth.org",\r
792 > -"87pr7gqidx.fsf@yoom.home.cworth.org",\r
793 > -"867hto2p0t.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",\r
794 > -"1258532999-9316-1-git-send-email-keithp@keithp.com",\r
795 > -"86aayk2rbj.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",\r
796 > -"86d43g2w3y.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",\r
797 > -"ddd65cda0911172214t60d22b63hcfeb5a19ab54a39b@mail.gmail.com",\r
798 > -"86einw2xof.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me",\r
799 > -"736613.51770.qm@web113505.mail.gq1.yahoo.com",\r
800 > -"1258520223-15328-1-git-send-email-jan@ryngle.com",\r
801 > -"ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com",\r
802 > -"1258510940-7018-1-git-send-email-stewart@flamingspork.com",\r
803 > -"yunzl6kd1w0.fsf@aiko.keithp.com",\r
804 > -"yun1vjwegii.fsf@aiko.keithp.com",\r
805 > -"yun3a4cegoa.fsf@aiko.keithp.com",\r
806 > -"1258509400-32511-1-git-send-email-stewart@flamingspork.com",\r
807 > -"1258506353-20352-1-git-send-email-stewart@flamingspork.com",\r
808 > -"20091118010116.GC25380@dottiness.seas.harvard.edu",\r
809 > -"20091118005829.GB25380@dottiness.seas.harvard.edu",\r
810 > -"20091118005040.GA25380@dottiness.seas.harvard.edu",\r
811 > -"cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com",\r
812 > -"1258500222-32066-1-git-send-email-ingmar@exherbo.org",\r
813 > -"20091117232137.GA7669@griffis1.net",\r
814 > -"20091118002059.067214ed@hikari",\r
815 > -"1258498485-sup-142@elly",\r
816 > -"f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com",\r
817 > -"f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com",\r
818 > -"1258496327-12086-1-git-send-email-jan@ryngle.com",\r
819 > -"1258493565-13508-1-git-send-email-keithp@keithp.com",\r
820 > -"yunaayketfm.fsf@aiko.keithp.com",\r
821 > -"yunbpj0etua.fsf@aiko.keithp.com",\r
822 > -"1258491078-29658-1-git-send-email-dottedmag@dottedmag.net",\r
823 > -"87fx8can9z.fsf@vertex.dottedmag",\r
824 > -"20091117203301.GV3165@dottiness.seas.harvard.edu",\r
825 > -"87lji4lx9v.fsf@yoom.home.cworth.org",\r
826 > -"cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com",\r
827 > -"87iqd9rn3l.fsf@vertex.dottedmag",\r
828 > -"20091117190054.GU3165@dottiness.seas.harvard.edu",\r
829 > -"87lji5cbwo.fsf@yoom.home.cworth.org",\r
830 > -"1258471718-6781-2-git-send-email-dottedmag@dottedmag.net",\r
831 > -"1258471718-6781-1-git-send-email-dottedmag@dottedmag.net"]\r
832 > +["4EFC743A.3060609@april.org"\r
833 > +, "877h1wv7mg.fsf@inf-8657.int-evry.fr"\r
834 > +, "1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk"\r
835 > +, "877htoqdbo.fsf@yoom.home.cworth.org"\r
836 > +, "878we4qdqf.fsf@yoom.home.cworth.org"\r
837 > +, "87aaykqe24.fsf@yoom.home.cworth.org"\r
838 > +, "87bpj0qeng.fsf@yoom.home.cworth.org"\r
839 > +, "87fx8cqf8v.fsf@yoom.home.cworth.org"\r
840 > +, "87hbssqfix.fsf@yoom.home.cworth.org"\r
841 > +, "87iqd8qgiz.fsf@yoom.home.cworth.org"\r
842 > +, "87k4xoqgnl.fsf@yoom.home.cworth.org"\r
843 > +, "87ocn0qh6d.fsf@yoom.home.cworth.org"\r
844 > +, "87pr7gqidx.fsf@yoom.home.cworth.org"\r
845 > +, "867hto2p0t.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me"\r
846 > +, "1258532999-9316-1-git-send-email-keithp@keithp.com"\r
847 > +, "86aayk2rbj.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me"\r
848 > +, "86d43g2w3y.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me"\r
849 > +, "ddd65cda0911172214t60d22b63hcfeb5a19ab54a39b@mail.gmail.com"\r
850 > +, "86einw2xof.fsf@fortitudo.i-did-not-set--mail-host-address--so-tickle-me"\r
851 > +, "736613.51770.qm@web113505.mail.gq1.yahoo.com"\r
852 > +, "1258520223-15328-1-git-send-email-jan@ryngle.com"\r
853 > +, "ddd65cda0911171950o4eea4389v86de9525e46052d3@mail.gmail.com"\r
854 > +, "1258510940-7018-1-git-send-email-stewart@flamingspork.com"\r
855 > +, "yunzl6kd1w0.fsf@aiko.keithp.com"\r
856 > +, "yun1vjwegii.fsf@aiko.keithp.com"\r
857 > +, "yun3a4cegoa.fsf@aiko.keithp.com"\r
858 > +, "1258509400-32511-1-git-send-email-stewart@flamingspork.com"\r
859 > +, "1258506353-20352-1-git-send-email-stewart@flamingspork.com"\r
860 > +, "20091118010116.GC25380@dottiness.seas.harvard.edu"\r
861 > +, "20091118005829.GB25380@dottiness.seas.harvard.edu"\r
862 > +, "20091118005040.GA25380@dottiness.seas.harvard.edu"\r
863 > +, "cf0c4d610911171623q3e27a0adx802e47039b57604b@mail.gmail.com"\r
864 > +, "1258500222-32066-1-git-send-email-ingmar@exherbo.org"\r
865 > +, "20091117232137.GA7669@griffis1.net"\r
866 > +, "20091118002059.067214ed@hikari"\r
867 > +, "1258498485-sup-142@elly"\r
868 > +, "f35dbb950911171438k5df6eb56k77b6c0944e2e79ae@mail.gmail.com"\r
869 > +, "f35dbb950911171435ieecd458o853c873e35f4be95@mail.gmail.com"\r
870 > +, "1258496327-12086-1-git-send-email-jan@ryngle.com"\r
871 > +, "1258493565-13508-1-git-send-email-keithp@keithp.com"\r
872 > +, "yunaayketfm.fsf@aiko.keithp.com"\r
873 > +, "yunbpj0etua.fsf@aiko.keithp.com"\r
874 > +, "1258491078-29658-1-git-send-email-dottedmag@dottedmag.net"\r
875 > +, "87fx8can9z.fsf@vertex.dottedmag"\r
876 > +, "20091117203301.GV3165@dottiness.seas.harvard.edu"\r
877 > +, "87lji4lx9v.fsf@yoom.home.cworth.org"\r
878 > +, "cf0c4d610911171136h1713aa59w9cf9aa31f052ad0a@mail.gmail.com"\r
879 > +, "87iqd9rn3l.fsf@vertex.dottedmag"\r
880 > +, "20091117190054.GU3165@dottiness.seas.harvard.edu"\r
881 > +, "87lji5cbwo.fsf@yoom.home.cworth.org"\r
882 > +, "1258471718-6781-2-git-send-email-dottedmag@dottedmag.net"\r
883 > +, "1258471718-6781-1-git-send-email-dottedmag@dottedmag.net"\r
884 > +]\r
885 >  EOF\r
886 >  test_expect_equal_file OUTPUT EXPECTED\r
887 >  \r
888 > @@ -242,59 +244,60 @@ test_expect_equal_file OUTPUT EXPECTED\r
889 >  test_begin_subtest "--output=files --format=json"\r
890 >  notmuch search --format=json --output=files '*' | sed -e "s,$MAIL_DIR,MAIL_DIR," >OUTPUT\r
891 >  cat <<EOF >EXPECTED\r
892 > -["MAIL_DIR/cur/52:2,",\r
893 > -"MAIL_DIR/cur/53:2,",\r
894 > -"MAIL_DIR/cur/50:2,",\r
895 > -"MAIL_DIR/cur/49:2,",\r
896 > -"MAIL_DIR/cur/48:2,",\r
897 > -"MAIL_DIR/cur/47:2,",\r
898 > -"MAIL_DIR/cur/46:2,",\r
899 > -"MAIL_DIR/cur/45:2,",\r
900 > -"MAIL_DIR/cur/44:2,",\r
901 > -"MAIL_DIR/cur/43:2,",\r
902 > -"MAIL_DIR/cur/42:2,",\r
903 > -"MAIL_DIR/cur/41:2,",\r
904 > -"MAIL_DIR/cur/40:2,",\r
905 > -"MAIL_DIR/cur/39:2,",\r
906 > -"MAIL_DIR/cur/38:2,",\r
907 > -"MAIL_DIR/cur/37:2,",\r
908 > -"MAIL_DIR/cur/36:2,",\r
909 > -"MAIL_DIR/cur/35:2,",\r
910 > -"MAIL_DIR/cur/34:2,",\r
911 > -"MAIL_DIR/cur/33:2,",\r
912 > -"MAIL_DIR/cur/32:2,",\r
913 > -"MAIL_DIR/cur/31:2,",\r
914 > -"MAIL_DIR/cur/30:2,",\r
915 > -"MAIL_DIR/cur/29:2,",\r
916 > -"MAIL_DIR/cur/28:2,",\r
917 > -"MAIL_DIR/cur/27:2,",\r
918 > -"MAIL_DIR/cur/26:2,",\r
919 > -"MAIL_DIR/cur/25:2,",\r
920 > -"MAIL_DIR/cur/24:2,",\r
921 > -"MAIL_DIR/cur/23:2,",\r
922 > -"MAIL_DIR/cur/22:2,",\r
923 > -"MAIL_DIR/cur/21:2,",\r
924 > -"MAIL_DIR/cur/19:2,",\r
925 > -"MAIL_DIR/cur/18:2,",\r
926 > -"MAIL_DIR/cur/51:2,",\r
927 > -"MAIL_DIR/cur/20:2,",\r
928 > -"MAIL_DIR/cur/17:2,",\r
929 > -"MAIL_DIR/cur/16:2,",\r
930 > -"MAIL_DIR/cur/15:2,",\r
931 > -"MAIL_DIR/cur/14:2,",\r
932 > -"MAIL_DIR/cur/13:2,",\r
933 > -"MAIL_DIR/cur/12:2,",\r
934 > -"MAIL_DIR/cur/11:2,",\r
935 > -"MAIL_DIR/cur/10:2,",\r
936 > -"MAIL_DIR/cur/09:2,",\r
937 > -"MAIL_DIR/cur/08:2,",\r
938 > -"MAIL_DIR/cur/06:2,",\r
939 > -"MAIL_DIR/cur/05:2,",\r
940 > -"MAIL_DIR/cur/04:2,",\r
941 > -"MAIL_DIR/cur/03:2,",\r
942 > -"MAIL_DIR/cur/07:2,",\r
943 > -"MAIL_DIR/cur/02:2,",\r
944 > -"MAIL_DIR/cur/01:2,"]\r
945 > +["MAIL_DIR/cur/52:2,"\r
946 > +, "MAIL_DIR/cur/53:2,"\r
947 > +, "MAIL_DIR/cur/50:2,"\r
948 > +, "MAIL_DIR/cur/49:2,"\r
949 > +, "MAIL_DIR/cur/48:2,"\r
950 > +, "MAIL_DIR/cur/47:2,"\r
951 > +, "MAIL_DIR/cur/46:2,"\r
952 > +, "MAIL_DIR/cur/45:2,"\r
953 > +, "MAIL_DIR/cur/44:2,"\r
954 > +, "MAIL_DIR/cur/43:2,"\r
955 > +, "MAIL_DIR/cur/42:2,"\r
956 > +, "MAIL_DIR/cur/41:2,"\r
957 > +, "MAIL_DIR/cur/40:2,"\r
958 > +, "MAIL_DIR/cur/39:2,"\r
959 > +, "MAIL_DIR/cur/38:2,"\r
960 > +, "MAIL_DIR/cur/37:2,"\r
961 > +, "MAIL_DIR/cur/36:2,"\r
962 > +, "MAIL_DIR/cur/35:2,"\r
963 > +, "MAIL_DIR/cur/34:2,"\r
964 > +, "MAIL_DIR/cur/33:2,"\r
965 > +, "MAIL_DIR/cur/32:2,"\r
966 > +, "MAIL_DIR/cur/31:2,"\r
967 > +, "MAIL_DIR/cur/30:2,"\r
968 > +, "MAIL_DIR/cur/29:2,"\r
969 > +, "MAIL_DIR/cur/28:2,"\r
970 > +, "MAIL_DIR/cur/27:2,"\r
971 > +, "MAIL_DIR/cur/26:2,"\r
972 > +, "MAIL_DIR/cur/25:2,"\r
973 > +, "MAIL_DIR/cur/24:2,"\r
974 > +, "MAIL_DIR/cur/23:2,"\r
975 > +, "MAIL_DIR/cur/22:2,"\r
976 > +, "MAIL_DIR/cur/21:2,"\r
977 > +, "MAIL_DIR/cur/19:2,"\r
978 > +, "MAIL_DIR/cur/18:2,"\r
979 > +, "MAIL_DIR/cur/51:2,"\r
980 > +, "MAIL_DIR/cur/20:2,"\r
981 > +, "MAIL_DIR/cur/17:2,"\r
982 > +, "MAIL_DIR/cur/16:2,"\r
983 > +, "MAIL_DIR/cur/15:2,"\r
984 > +, "MAIL_DIR/cur/14:2,"\r
985 > +, "MAIL_DIR/cur/13:2,"\r
986 > +, "MAIL_DIR/cur/12:2,"\r
987 > +, "MAIL_DIR/cur/11:2,"\r
988 > +, "MAIL_DIR/cur/10:2,"\r
989 > +, "MAIL_DIR/cur/09:2,"\r
990 > +, "MAIL_DIR/cur/08:2,"\r
991 > +, "MAIL_DIR/cur/06:2,"\r
992 > +, "MAIL_DIR/cur/05:2,"\r
993 > +, "MAIL_DIR/cur/04:2,"\r
994 > +, "MAIL_DIR/cur/03:2,"\r
995 > +, "MAIL_DIR/cur/07:2,"\r
996 > +, "MAIL_DIR/cur/02:2,"\r
997 > +, "MAIL_DIR/cur/01:2,"\r
998 > +]\r
999 >  EOF\r
1000 >  test_expect_equal_file OUTPUT EXPECTED\r
1001 >  \r
1002 > @@ -311,10 +314,11 @@ test_expect_equal_file OUTPUT EXPECTED\r
1003 >  test_begin_subtest "--output=tags --format=json"\r
1004 >  notmuch search --format=json --output=tags '*' >OUTPUT\r
1005 >  cat <<EOF >EXPECTED\r
1006 > -["attachment",\r
1007 > -"inbox",\r
1008 > -"signed",\r
1009 > -"unread"]\r
1010 > +["attachment"\r
1011 > +, "inbox"\r
1012 > +, "signed"\r
1013 > +, "unread"\r
1014 > +]\r
1015 >  EOF\r
1016 >  test_expect_equal_file OUTPUT EXPECTED\r
1017 >  \r