Flat search and threaded views
[notmuch-archives.git] / 40 / 83d8704b89f6de996db3300ecd4617418b3cae
1 Return-Path: <markwalters1009@gmail.com>\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 6BB2B431FBD\r
6         for <notmuch@notmuchmail.org>; Sat, 24 Nov 2012 05:21:18 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: 0.201\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=0.201 tagged_above=-999 required=5\r
12         tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
13         FREEMAIL_ENVFROM_END_DIGIT=1, FREEMAIL_FROM=0.001,\r
14         RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
15 Received: from olra.theworths.org ([127.0.0.1])\r
16         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
17         with ESMTP id lUhXcg7esj4v for <notmuch@notmuchmail.org>;\r
18         Sat, 24 Nov 2012 05:21:16 -0800 (PST)\r
19 Received: from mail-wg0-f45.google.com (mail-wg0-f45.google.com\r
20  [74.125.82.45])        (using TLSv1 with cipher RC4-SHA (128/128 bits))        (No client\r
21  certificate requested) by olra.theworths.org (Postfix) with ESMTPS id\r
22  0F303431FAF    for <notmuch@notmuchmail.org>; Sat, 24 Nov 2012 05:21:15 -0800\r
23  (PST)\r
24 Received: by mail-wg0-f45.google.com with SMTP id dq11so3973532wgb.2\r
25         for <notmuch@notmuchmail.org>; Sat, 24 Nov 2012 05:21:15 -0800 (PST)\r
26 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113;\r
27         h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;\r
28         bh=fVtRUudxpPp9qg10ROX/1HSFdBG9fBa+e0lHY46xMUE=;\r
29         b=AsCAuZGpCYh73jZdYWopFkZJFACI7uEC5+bsbtaEIlKKXQ1uBsWY3oTLknxVWCxqz5\r
30         IftB7iE54FOmIOwAdgZk/FTiuejizmGN71588qeYjeY02fNvUXfPHvYl79W7TgRG9I4b\r
31         ASO2fPn33M2/OLoRBh7OSkGbAqlsVhcV5ZtX2Os28wM9lbErIznBMPSeWdcoCmIDkJPd\r
32         V5K9qm0zBxHsPkDYc7fyKibynFIE3LZwdTIYE+lf0EaFvQYYF9HjJ/EpzoLM81NLvS2R\r
33         yIgNNC9ZkyNSK0hP1LQ++w2m/notz0qMBRlpMIUoux+Q70OeOc9pMwtKH6rYb8aRzVp4\r
34         VSSg==\r
35 Received: by 10.180.90.70 with SMTP id bu6mr13655680wib.20.1353763275642;\r
36         Sat, 24 Nov 2012 05:21:15 -0800 (PST)\r
37 Received: from localhost (93-97-24-31.zone5.bethere.co.uk. [93.97.24.31])\r
38         by mx.google.com with ESMTPS id i2sm12683344wiw.3.2012.11.24.05.21.14\r
39         (version=TLSv1/SSLv3 cipher=OTHER);\r
40         Sat, 24 Nov 2012 05:21:14 -0800 (PST)\r
41 From: markwalters1009 <markwalters1009@gmail.com>\r
42 To: notmuch@notmuchmail.org\r
43 Subject: [PATCH v2 6/7] cli: allow search mode to include msg-ids with JSON\r
44         output\r
45 Date: Sat, 24 Nov 2012 13:20:55 +0000\r
46 Message-Id: <1353763256-32336-7-git-send-email-markwalters1009@gmail.com>\r
47 X-Mailer: git-send-email 1.7.9.1\r
48 In-Reply-To: <1353763256-32336-1-git-send-email-markwalters1009@gmail.com>\r
49 References: <1353763256-32336-1-git-send-email-markwalters1009@gmail.com>\r
50 X-BeenThere: notmuch@notmuchmail.org\r
51 X-Mailman-Version: 2.1.13\r
52 Precedence: list\r
53 List-Id: "Use and development of the notmuch mail system."\r
54         <notmuch.notmuchmail.org>\r
55 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
56         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
57 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
58 List-Post: <mailto:notmuch@notmuchmail.org>\r
59 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
60 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
61         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
62 X-List-Received-Date: Sat, 24 Nov 2012 13:21:18 -0000\r
63 \r
64 From: Mark Walters <markwalters1009@gmail.com>\r
65 \r
66 This adds a --queries=true option which modifies the summary output of\r
67 notmuch search by including two extra query strings with each result:\r
68 one query string specifies all matching messages and one query string\r
69 all non-matching messages. Currently these are just lists of message\r
70 ids joined with " or " but that could change in future.\r
71 \r
72 Currently this is not implemented for text format.\r
73 ---\r
74  notmuch-search.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++---\r
75  1 files changed, 89 insertions(+), 6 deletions(-)\r
76 \r
77 diff --git a/notmuch-search.c b/notmuch-search.c\r
78 index 830c4e4..c8fc9a6 100644\r
79 --- a/notmuch-search.c\r
80 +++ b/notmuch-search.c\r
81 @@ -26,7 +26,8 @@ typedef enum {\r
82      OUTPUT_THREADS,\r
83      OUTPUT_MESSAGES,\r
84      OUTPUT_FILES,\r
85 -    OUTPUT_TAGS\r
86 +    OUTPUT_TAGS,\r
87 +    OUTPUT_SUMMARY_WITH_QUERIES\r
88  } output_t;\r
89  \r
90  static char *\r
91 @@ -46,6 +47,57 @@ sanitize_string (const void *ctx, const char *str)\r
92      return out;\r
93  }\r
94  \r
95 +/* This function takes a message id and returns an escaped string\r
96 + * which can be used as a Xapian query. This involves prefixing with\r
97 + * `id:', putting the id inside double quotes, and doubling any\r
98 + * occurence of a double quote in the message id itself.*/\r
99 +static char *\r
100 +xapian_escape_id (const void *ctx,\r
101 +          const char *msg_id)\r
102 +{\r
103 +    const char *c;\r
104 +    char *escaped_msg_id;\r
105 +    escaped_msg_id = talloc_strdup (ctx, "id:\"");\r
106 +    for (c=msg_id; *c; c++)\r
107 +       if (*c == '"')\r
108 +           escaped_msg_id = talloc_asprintf_append (escaped_msg_id, "\"\"");\r
109 +       else\r
110 +           escaped_msg_id = talloc_asprintf_append (escaped_msg_id, "%c", *c);\r
111 +    escaped_msg_id = talloc_asprintf_append (escaped_msg_id, "\"");\r
112 +    return escaped_msg_id;\r
113 +}\r
114 +\r
115 +static char *\r
116 +output_msg_query (const void *ctx,\r
117 +               sprinter_t *format,\r
118 +               notmuch_bool_t matching,\r
119 +               notmuch_bool_t first,\r
120 +               notmuch_messages_t *messages)\r
121 +{\r
122 +    notmuch_message_t *message;\r
123 +    char *query, *escaped_msg_id;\r
124 +    query = talloc_strdup (ctx, "");\r
125 +    for (;\r
126 +        notmuch_messages_valid (messages);\r
127 +        notmuch_messages_move_to_next (messages))\r
128 +    {\r
129 +       message = notmuch_messages_get (messages);\r
130 +       if (notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH) == matching) {\r
131 +           escaped_msg_id = xapian_escape_id (ctx, notmuch_message_get_message_id (message));\r
132 +           if (first) {\r
133 +               query = talloc_asprintf_append (query, "%s", escaped_msg_id);\r
134 +               first = FALSE;\r
135 +           }\r
136 +           else\r
137 +               query = talloc_asprintf_append (query, " or %s", escaped_msg_id);\r
138 +           talloc_free (escaped_msg_id);\r
139 +       }\r
140 +       /* output_msg_query already starts with an ` or' */\r
141 +       query = talloc_asprintf_append (query, "%s", output_msg_query (ctx, format, matching, first, notmuch_message_get_replies (message)));\r
142 +    }\r
143 +    return query;\r
144 +}\r
145 +\r
146  static int\r
147  do_search_threads (sprinter_t *format,\r
148                    notmuch_query_t *query,\r
149 @@ -88,7 +140,7 @@ do_search_threads (sprinter_t *format,\r
150             format->string (format,\r
151                             notmuch_thread_get_thread_id (thread));\r
152             format->separator (format);\r
153 -       } else { /* output == OUTPUT_SUMMARY */\r
154 +       } else { /* output == OUTPUT_SUMMARY or OUTPUT_SUMMARY_WITH_QUERIES */\r
155             void *ctx_quote = talloc_new (thread);\r
156             const char *authors = notmuch_thread_get_authors (thread);\r
157             const char *subject = notmuch_thread_get_subject (thread);\r
158 @@ -108,7 +160,7 @@ do_search_threads (sprinter_t *format,\r
159             relative_date = notmuch_time_relative_date (ctx_quote, date);\r
160  \r
161             if (format->is_text_printer) {\r
162 -                /* Special case for the text formatter */\r
163 +               /* Special case for the text formatter */\r
164                 printf ("thread:%s %12s [%d/%d] %s; %s (",\r
165                         thread_id,\r
166                         relative_date,\r
167 @@ -133,8 +185,6 @@ do_search_threads (sprinter_t *format,\r
168                 format->string (format, subject);\r
169             }\r
170  \r
171 -           talloc_free (ctx_quote);\r
172 -\r
173             format->map_key (format, "tags");\r
174             format->begin_list (format);\r
175  \r
176 @@ -145,7 +195,7 @@ do_search_threads (sprinter_t *format,\r
177                 const char *tag = notmuch_tags_get (tags);\r
178  \r
179                 if (format->is_text_printer) {\r
180 -                  /* Special case for the text formatter */\r
181 +                   /* Special case for the text formatter */\r
182                     if (first_tag)\r
183                         first_tag = FALSE;\r
184                     else\r
185 @@ -160,8 +210,25 @@ do_search_threads (sprinter_t *format,\r
186                 printf (")");\r
187  \r
188             format->end (format);\r
189 +\r
190 +           if (output == OUTPUT_SUMMARY_WITH_QUERIES) {\r
191 +               char *query;\r
192 +               query = output_msg_query (ctx_quote, format, TRUE, TRUE, notmuch_thread_get_toplevel_messages (thread));\r
193 +               if (strlen (query)) {\r
194 +                   format->map_key (format, "matching_msg_query");\r
195 +                   format->string (format, query);\r
196 +               }\r
197 +               query = output_msg_query (ctx_quote, format, FALSE, TRUE, notmuch_thread_get_toplevel_messages (thread));\r
198 +               if (strlen (query)) {\r
199 +                   format->map_key (format, "nonmatching_msg_query");\r
200 +                   format->string (format, query);\r
201 +               }\r
202 +           }\r
203 +\r
204             format->end (format);\r
205             format->separator (format);\r
206 +\r
207 +           talloc_free (ctx_quote);\r
208         }\r
209  \r
210         notmuch_thread_destroy (thread);\r
211 @@ -303,6 +370,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
212      int offset = 0;\r
213      int limit = -1; /* unlimited */\r
214      int exclude = EXCLUDE_TRUE;\r
215 +    notmuch_bool_t with_queries = FALSE;\r
216      unsigned int i;\r
217  \r
218      enum { NOTMUCH_FORMAT_JSON, NOTMUCH_FORMAT_TEXT }\r
219 @@ -323,12 +391,14 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
220                                   { "messages", OUTPUT_MESSAGES },\r
221                                   { "files", OUTPUT_FILES },\r
222                                   { "tags", OUTPUT_TAGS },\r
223 +                                 { "with-queries", OUTPUT_SUMMARY_WITH_QUERIES },\r
224                                   { 0, 0 } } },\r
225          { NOTMUCH_OPT_KEYWORD, &exclude, "exclude", 'x',\r
226            (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },\r
227                                    { "false", EXCLUDE_FALSE },\r
228                                    { "flag", EXCLUDE_FLAG },\r
229                                    { 0, 0 } } },\r
230 +        { NOTMUCH_OPT_BOOLEAN, &with_queries, "queries", 'b', 0 },\r
231         { NOTMUCH_OPT_INT, &offset, "offset", 'O', 0 },\r
232         { NOTMUCH_OPT_INT, &limit, "limit", 'L', 0  },\r
233         { 0, 0, 0, 0, 0 }\r
234 @@ -398,6 +468,19 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
235             notmuch_query_set_omit_excluded (query, FALSE);\r
236      }\r
237  \r
238 +    if (with_queries) {\r
239 +       if (format_sel == NOTMUCH_FORMAT_TEXT) {\r
240 +           fprintf (stderr, "Warning: --queries=true not implemented for text format.\n");\r
241 +           with_queries = FALSE;\r
242 +       }\r
243 +       if (output != OUTPUT_SUMMARY) {\r
244 +           fprintf (stderr, "Warning: --queries=true only implemented for --output=summary.\n");\r
245 +           with_queries = FALSE;\r
246 +       }\r
247 +    }\r
248 +\r
249 +    if (with_queries) output = OUTPUT_SUMMARY_WITH_QUERIES;\r
250 +\r
251      switch (output) {\r
252      default:\r
253      case OUTPUT_SUMMARY:\r
254 -- \r
255 1.7.9.1\r
256 \r