[PATCH 3/4] Add documentation for user.other_name
[notmuch-archives.git] / 0a / 674f25433f27fd2be8c147e6b7ebc18e142455
1 Return-Path: <bremner@tesseract.cs.unb.ca>\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 arlo.cworth.org (Postfix) with ESMTP id BDD866DE014D\r
6  for <notmuch@notmuchmail.org>; Mon, 27 Jun 2016 06:48:42 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at cworth.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.005\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.005 tagged_above=-999 required=5\r
12  tests=[AWL=-0.006, HEADER_FROM_DIFFERENT_DOMAINS=0.001]\r
13  autolearn=disabled\r
14 Received: from arlo.cworth.org ([127.0.0.1])\r
15  by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
16  with ESMTP id aPDJIOOf4Vrt for <notmuch@notmuchmail.org>;\r
17  Mon, 27 Jun 2016 06:48:34 -0700 (PDT)\r
18 Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])\r
19  by arlo.cworth.org (Postfix) with ESMTPS id F20FC6DE00CC\r
20  for <notmuch@notmuchmail.org>; Mon, 27 Jun 2016 06:48:33 -0700 (PDT)\r
21 Received: from remotemail by fethera.tethera.net with local (Exim 4.84)\r
22  (envelope-from <bremner@tesseract.cs.unb.ca>)\r
23  id 1bHWtZ-0001Xa-RZ; Mon, 27 Jun 2016 09:48:13 -0400\r
24 Received: (nullmailer pid 17561 invoked by uid 1000);\r
25  Mon, 27 Jun 2016 13:33:20 -0000\r
26 From: David Bremner <david@tethera.net>\r
27 To: notmuch@notmuchmail.org\r
28 Subject: [PATCH] lib: regexp matching in 'subject' and 'from'\r
29 Date: Mon, 27 Jun 2016 15:33:07 +0200\r
30 Message-Id: <1467034387-16885-1-git-send-email-david@tethera.net>\r
31 X-Mailer: git-send-email 2.8.1\r
32 MIME-Version: 1.0\r
33 Content-Type: text/plain; charset=UTF-8\r
34 Content-Transfer-Encoding: 8bit\r
35 X-BeenThere: notmuch@notmuchmail.org\r
36 X-Mailman-Version: 2.1.20\r
37 Precedence: list\r
38 List-Id: "Use and development of the notmuch mail system."\r
39  <notmuch.notmuchmail.org>\r
40 List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
41  <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
42 List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
43 List-Post: <mailto:notmuch@notmuchmail.org>\r
44 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
45 List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
46  <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
47 X-List-Received-Date: Mon, 27 Jun 2016 13:48:42 -0000\r
48 \r
49 the idea is that you can run\r
50 \r
51 % notmuch search re:subject:<your-favourite-regexp>\r
52 % notmuch search re:from:<your-favourite-regexp>'\r
53 \r
54 or\r
55 \r
56 % notmuch search subject:"your usual phrase search"\r
57 % notmuch search from:"usual phrase search"\r
58 \r
59 This should also work with bindings, since it extends the query parser.\r
60 \r
61 This is trivial to extend for other value slots, but currently the only\r
62 value slots are date, message_id, from, subject, and last_mod. Date is\r
63 already searchable, and message_id is not obviously useful to regex\r
64 match.\r
65 \r
66 This was originally written by Austin Clements, and ported to Xapian\r
67 field processors (from Austin's custom query parser) by yours truly.\r
68 ---\r
69 \r
70 This is the zero-th non-WIP version. Since the last version [1], I\r
71 have added some better error reporting for regexp syntax errors, tests\r
72 for two kinds of query syntax error, and some documentation for the\r
73 query syntax.\r
74 \r
75  doc/man7/notmuch-search-terms.rst |  17 +++++-\r
76  lib/Makefile.local                |   1 +\r
77  lib/database-private.h            |   1 +\r
78  lib/database.cc                   |   5 ++\r
79  lib/regexp-fields.cc              | 125 ++++++++++++++++++++++++++++++++++++++\r
80  lib/regexp-fields.h               |  77 +++++++++++++++++++++++\r
81  test/T630-regexp-query.sh         |  91 +++++++++++++++++++++++++++\r
82  7 files changed, 316 insertions(+), 1 deletion(-)\r
83  create mode 100644 lib/regexp-fields.cc\r
84  create mode 100644 lib/regexp-fields.h\r
85  create mode 100755 test/T630-regexp-query.sh\r
86 \r
87 diff --git a/doc/man7/notmuch-search-terms.rst b/doc/man7/notmuch-search-terms.rst\r
88 index 075f88c..6155406 100644\r
89 --- a/doc/man7/notmuch-search-terms.rst\r
90 +++ b/doc/man7/notmuch-search-terms.rst\r
91 @@ -58,6 +58,8 @@ indicate user-supplied values):\r
92  \r
93  -  query:<name>\r
94  \r
95 +- re:{subject,from}:<regex>\r
96 +\r
97  The **from:** prefix is used to match the name or address of the sender\r
98  of an email message.\r
99  \r
100 @@ -139,6 +141,12 @@ queries added with **notmuch-config(1)**. Named queries are only\r
101  available if notmuch is built with **Xapian Field Processors** (see\r
102  below).\r
103  \r
104 +The **re:<field>:** prefix can be used to restrict the results to\r
105 +those whose <field> matches the given regular expression (see\r
106 +**regex(7)**). Regular expression searches are only available if\r
107 +notmuch is built with **Xapian Field Processors** (see below), and\r
108 +currently only for the Subject and From fields.\r
109 +\r
110  Operators\r
111  ---------\r
112  \r
113 @@ -213,13 +221,19 @@ Boolean and Probabilistic Prefixes\r
114  ----------------------------------\r
115  \r
116  Xapian (and hence notmuch) prefixes are either **boolean**, supporting\r
117 -exact matches like "tag:inbox"  or **probabilistic**, supporting a more flexible **term** based searching. The prefixes currently supported by notmuch are as follows.\r
118 +exact matches like "tag:inbox" or **probabilistic**, supporting a more\r
119 +flexible **term** based searching. Certain **special** prefixes are\r
120 +processed by notmuch in a way not stricly fitting either of Xapian's\r
121 +built in styles. The prefixes currently supported by notmuch are as\r
122 +follows.\r
123  \r
124  \r
125  Boolean\r
126     **tag:**, **id:**, **thread:**, **folder:**, **path:**\r
127  Probabilistic\r
128     **from:**, **to:**, **subject:**, **attachment:**, **mimetype:**\r
129 +Special\r
130 +   **query:**, **re:<field>**\r
131  \r
132  Terms and phrases\r
133  -----------------\r
134 @@ -389,6 +403,7 @@ Currently the following features require field processor support:\r
135  \r
136  - non-range date queries, e.g. "date:today"\r
137  - named queries e.g. "query:my_special_query"\r
138 +- regular expression searches, e.g. "re:subject:^\\[SPAM\\]"\r
139  \r
140  SEE ALSO\r
141  ========\r
142 diff --git a/lib/Makefile.local b/lib/Makefile.local\r
143 index beb9635..68771e6 100644\r
144 --- a/lib/Makefile.local\r
145 +++ b/lib/Makefile.local\r
146 @@ -51,6 +51,7 @@ libnotmuch_cxx_srcs =         \\r
147         $(dir)/query.cc         \\r
148         $(dir)/query-fp.cc      \\r
149         $(dir)/config.cc        \\r
150 +       $(dir)/regexp-fields.cc     \\r
151         $(dir)/thread.cc\r
152  \r
153  libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)\r
154 diff --git a/lib/database-private.h b/lib/database-private.h\r
155 index ca71a92..900a989 100644\r
156 --- a/lib/database-private.h\r
157 +++ b/lib/database-private.h\r
158 @@ -186,6 +186,7 @@ struct _notmuch_database {\r
159  #if HAVE_XAPIAN_FIELD_PROCESSOR\r
160      Xapian::FieldProcessor *date_field_processor;\r
161      Xapian::FieldProcessor *query_field_processor;\r
162 +    Xapian::FieldProcessor *re_field_processor;\r
163  #endif\r
164      Xapian::ValueRangeProcessor *last_mod_range_processor;\r
165  };\r
166 diff --git a/lib/database.cc b/lib/database.cc\r
167 index afafe88..b52b62d 100644\r
168 --- a/lib/database.cc\r
169 +++ b/lib/database.cc\r
170 @@ -21,6 +21,7 @@\r
171  #include "database-private.h"\r
172  #include "parse-time-vrp.h"\r
173  #include "query-fp.h"\r
174 +#include "regexp-fields.h"\r
175  #include "string-util.h"\r
176  \r
177  #include <iostream>\r
178 @@ -1016,6 +1017,8 @@ notmuch_database_open_verbose (const char *path,\r
179         notmuch->query_parser->add_boolean_prefix("date", notmuch->date_field_processor);\r
180         notmuch->query_field_processor = new QueryFieldProcessor (*notmuch->query_parser, notmuch);\r
181         notmuch->query_parser->add_boolean_prefix("query", notmuch->query_field_processor);\r
182 +       notmuch->re_field_processor = new RegexpFieldProcessor (*notmuch->query_parser, notmuch);\r
183 +       notmuch->query_parser->add_boolean_prefix("re", notmuch->re_field_processor);\r
184  #endif\r
185         notmuch->last_mod_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:");\r
186  \r
187 @@ -1112,6 +1115,8 @@ notmuch_database_close (notmuch_database_t *notmuch)\r
188      notmuch->date_field_processor = NULL;\r
189      delete notmuch->query_field_processor;\r
190      notmuch->query_field_processor = NULL;\r
191 +    delete notmuch->re_field_processor;\r
192 +    notmuch->re_field_processor = NULL;\r
193  #endif\r
194  \r
195      return status;\r
196 diff --git a/lib/regexp-fields.cc b/lib/regexp-fields.cc\r
197 new file mode 100644\r
198 index 0000000..4d3d972\r
199 --- /dev/null\r
200 +++ b/lib/regexp-fields.cc\r
201 @@ -0,0 +1,125 @@\r
202 +/* regexp-fields.cc - "re:" field processor glue\r
203 + *\r
204 + * This file is part of notmuch.\r
205 + *\r
206 + * Copyright © 2015 Austin Clements\r
207 + * Copyright © 2016 David Bremner\r
208 + *\r
209 + * This program is free software: you can redistribute it and/or modify\r
210 + * it under the terms of the GNU General Public License as published by\r
211 + * the Free Software Foundation, either version 3 of the License, or\r
212 + * (at your option) any later version.\r
213 + *\r
214 + * This program is distributed in the hope that it will be useful,\r
215 + * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
216 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
217 + * GNU General Public License for more details.\r
218 + *\r
219 + * You should have received a copy of the GNU General Public License\r
220 + * along with this program.  If not, see https://www.gnu.org/licenses/ .\r
221 + *\r
222 + * Author: Austin Clements <aclements@csail.mit.edu>\r
223 + *                David Bremner <david@tethera.net>\r
224 + */\r
225 +\r
226 +#include "regexp-fields.h"\r
227 +#include "notmuch-private.h"\r
228 +\r
229 +#if HAVE_XAPIAN_FIELD_PROCESSOR\r
230 +RegexpPostingSource::RegexpPostingSource (Xapian::valueno slot, const std::string &regexp)\r
231 +    : slot_ (slot)\r
232 +{\r
233 +    int err = regcomp (&regexp_, regexp.c_str (), REG_EXTENDED | REG_NOSUB);\r
234 +\r
235 +    if (err != 0) {\r
236 +       size_t len = regerror (err, &regexp_, NULL, 0);\r
237 +       char *buffer = new char[len];\r
238 +       std::string msg;\r
239 +       (void) regerror (err, &regexp_, buffer, len);\r
240 +       msg.assign (buffer, len);\r
241 +       delete buffer;\r
242 +\r
243 +       throw Xapian::QueryParserError (msg);\r
244 +    }\r
245 +}\r
246 +\r
247 +RegexpPostingSource::~RegexpPostingSource ()\r
248 +{\r
249 +    regfree (&regexp_);\r
250 +}\r
251 +\r
252 +void\r
253 +RegexpPostingSource::init (const Xapian::Database &db)\r
254 +{\r
255 +    db_ = db;\r
256 +    it_ = db_.valuestream_begin (slot_);\r
257 +    end_ = db.valuestream_end (slot_);\r
258 +    started_ = false;\r
259 +}\r
260 +\r
261 +Xapian::doccount\r
262 +RegexpPostingSource::get_termfreq_min () const\r
263 +{\r
264 +    return 0;\r
265 +}\r
266 +\r
267 +Xapian::doccount\r
268 +RegexpPostingSource::get_termfreq_est () const\r
269 +{\r
270 +    return get_termfreq_max () / 2;\r
271 +}\r
272 +\r
273 +Xapian::doccount\r
274 +RegexpPostingSource::get_termfreq_max () const\r
275 +{\r
276 +    return db_.get_value_freq (slot_);\r
277 +}\r
278 +\r
279 +Xapian::docid\r
280 +RegexpPostingSource::get_docid () const\r
281 +{\r
282 +    return it_.get_docid ();\r
283 +}\r
284 +\r
285 +bool\r
286 +RegexpPostingSource::at_end () const\r
287 +{\r
288 +    return it_ == end_;\r
289 +}\r
290 +\r
291 +void\r
292 +RegexpPostingSource::next (unused (double min_wt))\r
293 +{\r
294 +    if (started_ && ! at_end ())\r
295 +       ++it_;\r
296 +    started_ = true;\r
297 +\r
298 +    for (; ! at_end (); ++it_) {\r
299 +       std::string value = *it_;\r
300 +       if (regexec (&regexp_, value.c_str (), 0, NULL, 0) == 0)\r
301 +           break;\r
302 +    }\r
303 +}\r
304 +\r
305 +static Xapian::valueno\r
306 +_find_slot (std::string prefix)\r
307 +{\r
308 +    if (prefix == "from")\r
309 +       return NOTMUCH_VALUE_FROM;\r
310 +    else if (prefix == "subject")\r
311 +       return NOTMUCH_VALUE_SUBJECT;\r
312 +    else\r
313 +       throw Xapian::QueryParserError ("unsupported regexp field '" + prefix + "'");\r
314 +}\r
315 +\r
316 +Xapian::Query\r
317 +RegexpFieldProcessor::operator() (const std::string & str)\r
318 +{\r
319 +    size_t pos = str.find_first_of (':');\r
320 +    std::string prefix = str.substr (0, pos);\r
321 +    std::string regexp = str.substr (pos + 1);\r
322 +\r
323 +    postings = new RegexpPostingSource (_find_slot (prefix), regexp);\r
324 +    return Xapian::Query (postings);\r
325 +}\r
326 +#endif\r
327 diff --git a/lib/regexp-fields.h b/lib/regexp-fields.h\r
328 new file mode 100644\r
329 index 0000000..2c9c2d7\r
330 --- /dev/null\r
331 +++ b/lib/regexp-fields.h\r
332 @@ -0,0 +1,77 @@\r
333 +/* regex-fields.h - xapian glue for semi-bruteforce regexp search\r
334 + *\r
335 + * This file is part of notmuch.\r
336 + *\r
337 + * Copyright © 2015 Austin Clements\r
338 + * Copyright © 2016 David Bremner\r
339 + *\r
340 + * This program is free software: you can redistribute it and/or modify\r
341 + * it under the terms of the GNU General Public License as published by\r
342 + * the Free Software Foundation, either version 3 of the License, or\r
343 + * (at your option) any later version.\r
344 + *\r
345 + * This program is distributed in the hope that it will be useful,\r
346 + * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
347 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
348 + * GNU General Public License for more details.\r
349 + *\r
350 + * You should have received a copy of the GNU General Public License\r
351 + * along with this program.  If not, see https://www.gnu.org/licenses/ .\r
352 + *\r
353 + * Author: Austin Clements <aclements@csail.mit.edu>\r
354 + *                David Bremner <david@tethera.net>\r
355 + */\r
356 +\r
357 +#ifndef NOTMUCH_REGEXP_FIELDS_H\r
358 +#define NOTMUCH_REGEXP_FIELDS_H\r
359 +#if HAVE_XAPIAN_FIELD_PROCESSOR\r
360 +#include <sys/types.h>\r
361 +#include <regex.h>\r
362 +#include <xapian.h>\r
363 +#include "notmuch-private.h"\r
364 +\r
365 +/* A posting source that returns documents where a value matches a\r
366 + * regexp.\r
367 + */\r
368 +class RegexpPostingSource : public Xapian::PostingSource\r
369 +{\r
370 + protected:\r
371 +    const Xapian::valueno slot_;\r
372 +    regex_t regexp_;\r
373 +    Xapian::Database db_;\r
374 +    bool started_;\r
375 +    Xapian::ValueIterator it_, end_;\r
376 +\r
377 +/* No copying */\r
378 +    RegexpPostingSource (const RegexpPostingSource &);\r
379 +    RegexpPostingSource &operator= (const RegexpPostingSource &);\r
380 +\r
381 + public:\r
382 +    RegexpPostingSource (Xapian::valueno slot, const std::string &regexp);\r
383 +    ~RegexpPostingSource ();\r
384 +    void init (const Xapian::Database &db);\r
385 +    Xapian::doccount get_termfreq_min () const;\r
386 +    Xapian::doccount get_termfreq_est () const;\r
387 +    Xapian::doccount get_termfreq_max () const;\r
388 +    Xapian::docid get_docid () const;\r
389 +    bool at_end () const;\r
390 +    void next (unused (double min_wt));\r
391 +};\r
392 +\r
393 +\r
394 +class RegexpFieldProcessor : public Xapian::FieldProcessor {\r
395 + protected:\r
396 +    Xapian::QueryParser &parser;\r
397 +    notmuch_database_t *notmuch;\r
398 +    RegexpPostingSource *postings = NULL;\r
399 +\r
400 + public:\r
401 +    RegexpFieldProcessor (Xapian::QueryParser &parser_, notmuch_database_t *notmuch_)\r
402 +       : parser(parser_), notmuch(notmuch_) { };\r
403 +\r
404 +    ~RegexpFieldProcessor () { delete postings; };\r
405 +\r
406 +    Xapian::Query operator()(const std::string & str);\r
407 +};\r
408 +#endif\r
409 +#endif /* NOTMUCH_REGEXP_FIELDS_H */\r
410 diff --git a/test/T630-regexp-query.sh b/test/T630-regexp-query.sh\r
411 new file mode 100755\r
412 index 0000000..3bbe47c\r
413 --- /dev/null\r
414 +++ b/test/T630-regexp-query.sh\r
415 @@ -0,0 +1,91 @@\r
416 +#!/usr/bin/env bash\r
417 +test_description='regular expression searches'\r
418 +. ./test-lib.sh || exit 1\r
419 +\r
420 +add_email_corpus\r
421 +\r
422 +\r
423 +if [ $NOTMUCH_HAVE_XAPIAN_FIELD_PROCESSOR -eq 1 ]; then\r
424 +\r
425 +    notmuch search --output=messages from:cworth > cworth.msg-ids\r
426 +\r
427 +    test_begin_subtest "regexp from search, case sensitive"\r
428 +    notmuch search --output=messages re:from:carl > OUTPUT\r
429 +    test_expect_equal_file /dev/null OUTPUT\r
430 +\r
431 +    test_begin_subtest "empty regexp or query"\r
432 +    notmuch search --output=messages re:from:carl or from:cworth > OUTPUT\r
433 +    test_expect_equal_file cworth.msg-ids OUTPUT\r
434 +\r
435 +    test_begin_subtest "non-empty regexp and query"\r
436 +    notmuch search  re:from:cworth and subject:patch > OUTPUT\r
437 +    cat <<EOF > EXPECTED\r
438 +thread:0000000000000008   2009-11-18 [1/2] Carl Worth| Alex Botero-Lowry; [notmuch] [PATCH] Error out if no query is supplied to search instead of going into an infinite loop (attachment inbox unread)\r
439 +thread:0000000000000007   2009-11-18 [1/2] Carl Worth| Ingmar Vanhassel; [notmuch] [PATCH] Typsos (inbox unread)\r
440 +thread:0000000000000018   2009-11-18 [1/2] Carl Worth| Jan Janak; [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)\r
441 +thread:0000000000000017   2009-11-18 [1/2] Carl Worth| Keith Packard; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)\r
442 +thread:0000000000000014   2009-11-18 [2/5] Carl Worth| Mikhail Gusarov, Keith Packard; [notmuch] [PATCH 1/2] Close message file after parsing message headers (inbox unread)\r
443 +thread:0000000000000001   2009-11-18 [1/1] Stewart Smith; [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (inbox unread)\r
444 +EOF\r
445 +    test_expect_equal_file EXPECTED OUTPUT\r
446 +\r
447 +    test_begin_subtest "regexp from search, duplicate term search"\r
448 +    notmuch search --output=messages re:from:cworth > OUTPUT\r
449 +    test_expect_equal_file cworth.msg-ids OUTPUT\r
450 +\r
451 +    test_begin_subtest "long enough regexp matches only desired senders"\r
452 +    notmuch search --output=messages 're:"from:C.* Wo"' > OUTPUT\r
453 +    test_expect_equal_file cworth.msg-ids OUTPUT\r
454 +\r
455 +    test_begin_subtest "shorter regexp matches one more sender"\r
456 +    notmuch search --output=messages 're:"from:C.* W"' > OUTPUT\r
457 +    (echo id:1258544095-16616-1-git-send-email-chris@chris-wilson.co.uk ; cat cworth.msg-ids) > EXPECTED\r
458 +    test_expect_equal_file EXPECTED OUTPUT\r
459 +\r
460 +    test_begin_subtest "regexp subject search, non-ASCII"\r
461 +    notmuch search --output=messages re:subject:accentué > OUTPUT\r
462 +    echo id:877h1wv7mg.fsf@inf-8657.int-evry.fr > EXPECTED\r
463 +    test_expect_equal_file EXPECTED OUTPUT\r
464 +\r
465 +    test_begin_subtest "regexp subject search, punctuation"\r
466 +    notmuch search   re:subject:\'X\' > OUTPUT\r
467 +    cat <<EOF > EXPECTED\r
468 +thread:0000000000000017   2009-11-18 [2/2] Keith Packard, Carl Worth; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)\r
469 +EOF\r
470 +    test_expect_equal_file EXPECTED OUTPUT\r
471 +\r
472 +    test_begin_subtest "regexp subject search, no punctuation"\r
473 +    notmuch search  re:subject:X > OUTPUT\r
474 +    cat <<EOF > EXPECTED\r
475 +thread:0000000000000017   2009-11-18 [2/2] Keith Packard, Carl Worth; [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (inbox unread)\r
476 +thread:000000000000000f   2009-11-18 [4/4] Jjgod Jiang, Alexander Botero-Lowry; [notmuch] Mac OS X/Darwin compatibility issues (inbox unread)\r
477 +EOF\r
478 +    test_expect_equal_file EXPECTED OUTPUT\r
479 +\r
480 +    test_begin_subtest "combine regexp from and subject"\r
481 +    notmuch search  re:subject:-C and re:from:.an.k > OUTPUT\r
482 +    cat <<EOF > EXPECTED\r
483 +thread:0000000000000018   2009-11-17 [1/2] Jan Janak| Carl Worth; [notmuch] [PATCH] Older versions of install do not support -C. (inbox unread)\r
484 +EOF\r
485 +    test_expect_equal_file EXPECTED OUTPUT\r
486 +\r
487 +    test_begin_subtest "bad subprefix"\r
488 +    notmuch search 're:unsupported:.*' 1>OUTPUT 2>&1\r
489 +    cat <<EOF > EXPECTED\r
490 +notmuch search: A Xapian exception occurred\r
491 +A Xapian exception occurred performing query: unsupported regexp field 'unsupported'\r
492 +Query string was: re:unsupported:.*\r
493 +EOF\r
494 +    test_expect_equal_file EXPECTED OUTPUT\r
495 +\r
496 +    test_begin_subtest "regexp error reporting"\r
497 +    notmuch search 're:from:unbalanced[' 1>OUTPUT 2>&1\r
498 +    cat <<EOF > EXPECTED\r
499 +notmuch search: A Xapian exception occurred\r
500 +A Xapian exception occurred performing query: Invalid regular expression\r
501 +Query string was: re:from:unbalanced[\r
502 +EOF\r
503 +    test_expect_equal_file EXPECTED OUTPUT\r
504 +fi\r
505 +\r
506 +test_done\r
507 -- \r
508 2.8.1\r
509 \r