Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / 5a / 866891e1612da6c1cc7f5125b1ccb8087f21ee
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
8 X-Spam-Flag: NO\r
9 X-Spam-Score: 0.001\r
10 X-Spam-Level: \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
13         autolearn=disabled\r
14 Received: from olra.theworths.org ([127.0.0.1])\r
15         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
16         with ESMTP id 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
26         lXqfDORnr1Ek2X\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
38 MIME-Version: 1.0\r
39 Content-Type: text/plain; charset=UTF-8\r
40 Content-Transfer-Encoding: 8bit\r
41 X-Y-GMX-Trusted: 0\r
42 X-BeenThere: notmuch@notmuchmail.org\r
43 X-Mailman-Version: 2.1.13\r
44 Precedence: list\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
55 \r
56 From: <craven@gmx.net>\r
57 \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
60 sprinter-json.c.\r
61 \r
62 The JSON tests are changed slightly in order to make them PASS for the\r
63 new structured output formatter.\r
64 \r
65 The Text tests pass without adaptation.\r
66 ---\r
67  notmuch-search.c | 292 +++++++++++--------------------------------------------\r
68  test/json        |  18 +---\r
69  2 files changed, 58 insertions(+), 252 deletions(-)\r
70 \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
75 @@ -19,6 +19,7 @@\r
76   */\r
77  \r
78  #include "notmuch-client.h"\r
79 +#include "sprinter.h"\r
80  \r
81  typedef enum {\r
82      OUTPUT_SUMMARY,\r
83 @@ -28,175 +29,8 @@ typedef enum {\r
84      OUTPUT_TAGS\r
85  } output_t;\r
86  \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
97 -                           const int total,\r
98 -                           const char *authors,\r
99 -                           const char *subject);\r
100 -    const char *tag_start;\r
101 -    const char *tag;\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
109 -\r
110 -static void\r
111 -format_item_id_text (const void *ctx,\r
112 -                    const char *item_type,\r
113 -                    const char *item_id);\r
114 -\r
115 -static void\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
120 -                   const int total,\r
121 -                   const char *authors,\r
122 -                   const char *subject);\r
123 -static const search_format_t format_text = {\r
124 -    "",\r
125 -       "",\r
126 -           format_item_id_text,\r
127 -           format_thread_text,\r
128 -           " (",\r
129 -               "%s", " ",\r
130 -           ")", "\n",\r
131 -       "",\r
132 -    "\n",\r
133 -    "",\r
134 -};\r
135 -\r
136 -static void\r
137 -format_item_id_json (const void *ctx,\r
138 -                    const char *item_type,\r
139 -                    const char *item_id);\r
140 -\r
141 -static void\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
146 -                   const int total,\r
147 -                   const char *authors,\r
148 -                   const char *subject);\r
149 -\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
153 -    "[",\r
154 -       "{",\r
155 -           format_item_id_json,\r
156 -           format_thread_json,\r
157 -           "\"tags\": [",\r
158 -               "\"%s\"", ", ",\r
159 -           "]", ",\n",\r
160 -       "}",\r
161 -    "]\n",\r
162 -    "]\n",\r
163 -};\r
164 -\r
165 -static void\r
166 -format_item_id_text (unused (const void *ctx),\r
167 -                    const char *item_type,\r
168 -                    const char *item_id)\r
169 -{\r
170 -    printf ("%s%s", item_type, item_id);\r
171 -}\r
172 -\r
173 -static char *\r
174 -sanitize_string (const void *ctx, const char *str)\r
175 -{\r
176 -    char *out, *loop;\r
177 -\r
178 -    if (NULL == str)\r
179 -       return NULL;\r
180 -\r
181 -    loop = out = talloc_strdup (ctx, str);\r
182 -\r
183 -    for (; *loop; loop++) {\r
184 -       if ((unsigned char)(*loop) < 32)\r
185 -           *loop = '?';\r
186 -    }\r
187 -    return out;\r
188 -}\r
189 -\r
190 -static void\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
195 -                   const int total,\r
196 -                   const char *authors,\r
197 -                   const char *subject)\r
198 -{\r
199 -    void *ctx_quote = talloc_new (ctx);\r
200 -\r
201 -    printf ("thread:%s %12s [%d/%d] %s; %s",\r
202 -           thread_id,\r
203 -           notmuch_time_relative_date (ctx, date),\r
204 -           matched,\r
205 -           total,\r
206 -           sanitize_string (ctx_quote, authors),\r
207 -           sanitize_string (ctx_quote, subject));\r
208 -\r
209 -    talloc_free (ctx_quote);\r
210 -}\r
211 -\r
212 -static void\r
213 -format_item_id_json (const void *ctx,\r
214 -                    unused (const char *item_type),\r
215 -                    const char *item_id)\r
216 -{\r
217 -    void *ctx_quote = talloc_new (ctx);\r
218 -\r
219 -    printf ("%s", json_quote_str (ctx_quote, item_id));\r
220 -\r
221 -    talloc_free (ctx_quote);\r
222 -    \r
223 -}\r
224 -\r
225 -static void\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
230 -                   const int total,\r
231 -                   const char *authors,\r
232 -                   const char *subject)\r
233 -{\r
234 -    void *ctx_quote = talloc_new (ctx);\r
235 -\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
244 -           date,\r
245 -           notmuch_time_relative_date (ctx, date),\r
246 -           matched,\r
247 -           total,\r
248 -           json_quote_str (ctx_quote, authors),\r
249 -           json_quote_str (ctx_quote, subject));\r
250 -\r
251 -    talloc_free (ctx_quote);\r
252 -}\r
253 -\r
254  static int\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
259                    output_t output,\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
263      time_t date;\r
264 -    int first_thread = 1;\r
265      int i;\r
266  \r
267      if (offset < 0) {\r
268 @@ -220,14 +53,12 @@ do_search_threads (const search_format_t *format,\r
269      if (threads == NULL)\r
270         return 1;\r
271  \r
272 -    fputs (format->results_start, stdout);\r
273 +    format->begin_list (format);\r
274  \r
275      for (i = 0;\r
276          notmuch_threads_valid (threads) && (limit < 0 || i < offset + limit);\r
277          notmuch_threads_move_to_next (threads), i++)\r
278      {\r
279 -       int first_tag = 1;\r
280 -\r
281         thread = notmuch_threads_get (threads);\r
282  \r
283         if (i < offset) {\r
284 @@ -235,60 +66,65 @@ do_search_threads (const search_format_t *format,\r
285             continue;\r
286         }\r
287  \r
288 -       if (! first_thread)\r
289 -           fputs (format->item_sep, stdout);\r
290 -\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
301 +\r
302 +           format->begin_map (format);\r
303  \r
304             if (sort == NOTMUCH_SORT_OLDEST_FIRST)\r
305                 date = notmuch_thread_get_oldest_date (thread);\r
306             else\r
307                 date = notmuch_thread_get_newest_date (thread);\r
308  \r
309 -           format->thread_summary (thread,\r
310 -                                   notmuch_thread_get_thread_id (thread),\r
311 -                                   date,\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
316 -\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
332 +\r
333 +           talloc_free (ctx_quote);\r
334 +\r
335 +           format->map_key (format, "tags");\r
336 +           format->begin_list (format);\r
337  \r
338             for (tags = notmuch_thread_get_tags (thread);\r
339                  notmuch_tags_valid (tags);\r
340                  notmuch_tags_move_to_next (tags))\r
341             {\r
342 -               if (! first_tag)\r
343 -                   fputs (format->tag_sep, stdout);\r
344 -               printf (format->tag, notmuch_tags_get (tags));\r
345 -               first_tag = 0;\r
346 -           }\r
347 +               const char *tag = notmuch_tags_get (tags);\r
348  \r
349 -           fputs (format->tag_end, stdout);\r
350 +               format->string (format, tag);\r
351 +           }\r
352  \r
353 -           fputs (format->item_end, stdout);\r
354 +           format->end (format);\r
355 +           format->end (format);\r
356 +           format->separator (format);\r
357         }\r
358  \r
359 -       first_thread = 0;\r
360 -\r
361         notmuch_thread_destroy (thread);\r
362      }\r
363  \r
364 -    if (first_thread)\r
365 -       fputs (format->results_null, stdout);\r
366 -    else\r
367 -       fputs (format->results_end, stdout);\r
368 +    format->end (format);\r
369  \r
370      return 0;\r
371  }\r
372  \r
373  static int\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
377                     output_t output,\r
378                     int offset,\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
384      int i;\r
385  \r
386      if (offset < 0) {\r
387 @@ -310,7 +145,7 @@ do_search_messages (const search_format_t *format,\r
388      if (messages == NULL)\r
389         return 1;\r
390  \r
391 -    fputs (format->results_start, stdout);\r
392 +    format->begin_list (format);\r
393  \r
394      for (i = 0;\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
399             {\r
400 -               if (! first_message)\r
401 -                   fputs (format->item_sep, stdout);\r
402 -\r
403 -               format->item_id (message, "",\r
404 -                                notmuch_filenames_get (filenames));\r
405 -\r
406 -               first_message = 0;\r
407 +               format->string (format, notmuch_filenames_get (filenames));\r
408 +               format->separator (format);\r
409             }\r
410 -           \r
411 +\r
412             notmuch_filenames_destroy( filenames );\r
413  \r
414         } else { /* output == OUTPUT_MESSAGES */\r
415 -           if (! first_message)\r
416 -               fputs (format->item_sep, stdout);\r
417 -\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
425         }\r
426  \r
427         notmuch_message_destroy (message);\r
428 @@ -353,23 +181,19 @@ do_search_messages (const search_format_t *format,\r
429  \r
430      notmuch_messages_destroy (messages);\r
431  \r
432 -    if (first_message)\r
433 -       fputs (format->results_null, stdout);\r
434 -    else\r
435 -       fputs (format->results_end, stdout);\r
436 +    format->end (format);\r
437  \r
438      return 0;\r
439  }\r
440  \r
441  static int\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
446  {\r
447      notmuch_messages_t *messages = NULL;\r
448      notmuch_tags_t *tags;\r
449      const char *tag;\r
450 -    int first_tag = 1;\r
451  \r
452      /* should the following only special case if no excluded terms\r
453       * specified? */\r
454 @@ -387,7 +211,7 @@ do_search_tags (notmuch_database_t *notmuch,\r
455      if (tags == NULL)\r
456         return 1;\r
457  \r
458 -    fputs (format->results_start, stdout);\r
459 +    format->begin_list (format);\r
460  \r
461      for (;\r
462          notmuch_tags_valid (tags);\r
463 @@ -395,12 +219,9 @@ do_search_tags (notmuch_database_t *notmuch,\r
464      {\r
465         tag = notmuch_tags_get (tags);\r
466  \r
467 -       if (! first_tag)\r
468 -           fputs (format->item_sep, stdout);\r
469 +       format->string (format, tag);\r
470 +       format->separator (format);\r
471  \r
472 -       format->item_id (tags, "", tag);\r
473 -\r
474 -       first_tag = 0;\r
475      }\r
476  \r
477      notmuch_tags_destroy (tags);\r
478 @@ -408,10 +229,7 @@ do_search_tags (notmuch_database_t *notmuch,\r
479      if (messages)\r
480         notmuch_messages_destroy (messages);\r
481  \r
482 -    if (first_tag)\r
483 -       fputs (format->results_null, stdout);\r
484 -    else\r
485 -       fputs (format->results_end, stdout);\r
486 +    format->end (format);\r
487  \r
488      return 0;\r
489  }\r
490 @@ -430,7 +248,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
491      notmuch_query_t *query;\r
492      char *query_str;\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
498      int offset = 0;\r
499 @@ -475,10 +293,10 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
500  \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
505         break;\r
506      case NOTMUCH_FORMAT_JSON:\r
507 -       format = &format_json;\r
508 +       format = sprinter_json_create (ctx, stdout);\r
509         break;\r
510      }\r
511  \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
515  \r
516 +    talloc_free (format);\r
517 +\r
518      return ret;\r
519  }\r
520 diff --git a/test/json b/test/json\r
521 index 6439788..f0ebf08 100755\r
522 --- a/test/json\r
523 +++ b/test/json\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
531 -\"matched\": 1,\r
532 -\"total\": 1,\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
537  \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
547 -\"matched\": 1,\r
548 -\"total\": 1,\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
553  \r
554  test_done\r
555 -- \r
556 1.7.11.1\r
557 \r