Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / f7 / b93dff3236b198b27cc2bc190f5c4836f40a69
1 Return-Path: <pieter@praet.org>\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 24935431FD0\r
6         for <notmuch@notmuchmail.org>; Mon, 11 Jul 2011 13:43:26 -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 koDr0Kmwy0I5 for <notmuch@notmuchmail.org>;\r
16         Mon, 11 Jul 2011 13:43:23 -0700 (PDT)\r
17 Received: from mail-wy0-f181.google.com (mail-wy0-f181.google.com\r
18         [74.125.82.181]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
19         (No client certificate requested)\r
20         by olra.theworths.org (Postfix) with ESMTPS id 6E8AA431FB6\r
21         for <notmuch@notmuchmail.org>; Mon, 11 Jul 2011 13:43:23 -0700 (PDT)\r
22 Received: by wyh22 with SMTP id 22so3208041wyh.26\r
23         for <notmuch@notmuchmail.org>; Mon, 11 Jul 2011 13:43:22 -0700 (PDT)\r
24 Received: by 10.216.235.134 with SMTP id u6mr3358534weq.99.1310417001892;\r
25         Mon, 11 Jul 2011 13:43:21 -0700 (PDT)\r
26 Received: from localhost ([109.131.120.63])\r
27         by mx.google.com with ESMTPS id gb1sm10317138wbb.54.2011.07.11.13.43.18\r
28         (version=TLSv1/SSLv3 cipher=OTHER);\r
29         Mon, 11 Jul 2011 13:43:20 -0700 (PDT)\r
30 From: Pieter Praet <pieter@praet.org>\r
31 To: Austin Clements <amdragon@MIT.EDU>\r
32 Subject: [PATCH v2] emacs: bad regexp @ `notmuch-search-process-filter'\r
33 Date: Mon, 11 Jul 2011 22:43:13 +0200\r
34 Message-Id: <1310416993-31031-1-git-send-email-pieter@praet.org>\r
35 X-Mailer: git-send-email 1.7.5.4\r
36 In-Reply-To: <20110705214234.GA15360@mit.edu>\r
37 References: <20110705214234.GA15360@mit.edu>\r
38 Cc: Notmuch Mail <notmuch@notmuchmail.org>\r
39 X-BeenThere: notmuch@notmuchmail.org\r
40 X-Mailman-Version: 2.1.13\r
41 Precedence: list\r
42 List-Id: "Use and development of the notmuch mail system."\r
43         <notmuch.notmuchmail.org>\r
44 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
45         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
46 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
47 List-Post: <mailto:notmuch@notmuchmail.org>\r
48 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
49 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
50         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
51 X-List-Received-Date: Mon, 11 Jul 2011 20:43:26 -0000\r
52 \r
53 \r
54 TL;DR: I can haz regex pl0x?\r
55 \r
56 \r
57 I've updated the regex a bit to prevent it from choking on the whole\r
58 "parens in subject vs. parens around tags vs. parens around matching\r
59 Message-Id's" deal, but it still causes errors in the search buffer due\r
60 to the list of Message-Id's being cut off at a seemingly arbitrary point,\r
61 and this for *different* results on pretty much every refresh.\r
62 \r
63 All tests pass, except for the ones I've mentioned before [1] (which\r
64 don't test anything tagging-related, just `notmuch-show'), though even\r
65 those fail to fail consistently :<. This variability can't be related to\r
66 residual files, as I always run the test suite like this:\r
67 \r
68   rm -rf /dev/shm/notmuch/* && make test OPTIONS="--root=/dev/shm/notmuch"\r
69 \r
70 \r
71 So, to keep this on track for 0.7 whilst keeping myself from having to\r
72 send spammerific amounts of patches, I've squashed the whole deal in\r
73 this single patch. Don't worry though, it's all quite grokkable:\r
74 \r
75 \r
76 notmuch-search.c\r
77 \r
78 - Make `notmuch search' *only* append results with their Message-Id's\r
79   when supplied with the "--output=summary-ids" option, to prevent a\r
80   slew of failing tests obscuring the relevant ones.\r
81 \r
82 \r
83 emacs/notmuch.el\r
84 \r
85 - Make `notmuch-search' run the notmuch binary with the "--output=summary-ids"\r
86   option, to receive search results appended with their lists of Message-Id's.\r
87 \r
88 - Update the regex @ `notmuch-search-process-filter' to include a new atom,\r
89   which matches the list of Message-Id's at the end of every search result\r
90   returned by the notmuch binary.\r
91   To each individual result in the search buffer, this matched string is\r
92   added as a text property called `notmuch-search-msgids'.\r
93 \r
94 - Add 2 functions to return the `notmuch-search-msgids' property of search\r
95   results: `notmuch-search-find-msgids', `notmuch-search-find-msgids-region'.\r
96 \r
97 - Add a function to stash the Message-Id's of (a region of) search results:\r
98   `notmuch-search-stash-msgids', bound to "m" in `notmuch-search-stash-map'.\r
99   Mainly for testing purposes.\r
100 \r
101 - Merge `notmuch-call-notmuch-process' into `notmuch-tag':\r
102   `notmuch-tag' was the only thing making use of `notmuch-call-notmuch-process',\r
103   and the extra layer of abstraction would complicate making `notmuch-tag' send\r
104   arguments on stdin (see next point).\r
105 \r
106 - Make `notmuch-tag' send its query string on stdin:\r
107   Instead of providing the query string as a (potentially very long) command\r
108   line argument, `notmuch-tag' now dumps it into a temporary buffer, which\r
109   `call-process-region' sends to `notmuch-command' on stdin.\r
110   This is needed to circumvent "$command: arg list too long" errors due\r
111   to command line argument length limitations imposed by the kernel (ARG_MAX).\r
112 \r
113 - Fix the actual bug(s) this patch series is intended to address by making\r
114   the tagging functions procure their targets from the `notmuch-search-msgids'\r
115   property with `notmuch-search-find-msgids-region', instead of using x:\r
116   - `notmuch-search-add-tag-region'    (x = `notmuch-search-find-thread-id-region')\r
117   - `notmuch-search-remove-tag-region' (x = `notmuch-search-find-thread-id-region')\r
118   - `notmuch-search-remove-tag'        (x = `notmuch-search-find-thread-id-region')\r
119   - `notmuch-search-operate-all'       (x = `notmuch-search-query-string')\r
120 \r
121 \r
122 test/emacs, test/emacs-search-operate-all, test/notmuch-test\r
123 \r
124 - Expand the test suite to also cover:\r
125   - Tagging messages with `notmuch-search-operate-all'.\r
126   - Tagging messages to which a reply is sent. For this I also needed to\r
127     correct the title of an existing test, and add a test for sending\r
128     replies from within Emacs.\r
129 \r
130 \r
131 Side note:\r
132   After playing around with Austin's new patch for a bit, I've come to the\r
133   conclusion that making a clear distinction between matched and unmatched\r
134   messages in the binary's output *is* the way to go, but in the case of\r
135   `notmuch-search-operate-all', this capability shouldn't be leveraged.\r
136 \r
137   The way `notmuch-search-operate-all' currently works, i.e. operate on\r
138   matched *messages* instead of matched *threads*, is not only counter-\r
139   intuitive (same as it would be for `notmuch-search-add-tag' and\r
140   `notmuch-search-remove-tag' [2]), but semantically incorrect as well:\r
141   Its name implies operating on *all* that is visible in the current\r
142   buffer, instead of only a subset.\r
143 \r
144 \r
145 Peace\r
146 \r
147 [1] id:"1310307099-25197-1-git-send-email-pieter@praet.org"\r
148 [2] id:"e8c5fbf4-4dfa-461a-8f5c-6c696291a270@email.android.com"\r
149 \r
150 \r
151 Signed-off-by: Pieter Praet <pieter@praet.org>\r
152 ---\r
153  emacs/notmuch.el              |   93 ++++++++++++++++++++++++++++-------------\r
154  notmuch-search.c              |    6 ++-\r
155  test/emacs                    |   49 +++++++++++++++++++++-\r
156  test/emacs-search-operate-all |   29 +++++++++++++\r
157  test/notmuch-test             |    1 +\r
158  5 files changed, 147 insertions(+), 31 deletions(-)\r
159  create mode 100755 test/emacs-search-operate-all\r
160 \r
161 diff --git a/emacs/notmuch.el b/emacs/notmuch.el\r
162 index f11ec24..400adcc 100644\r
163 --- a/emacs/notmuch.el\r
164 +++ b/emacs/notmuch.el\r
165 @@ -226,6 +226,7 @@ For a mouse binding, return nil."\r
166  (defvar notmuch-search-stash-map\r
167    (let ((map (make-sparse-keymap)))\r
168      (define-key map "i" 'notmuch-search-stash-thread-id)\r
169 +    (define-key map "m" 'notmuch-search-stash-msgids)\r
170      map)\r
171    "Submap for stash commands")\r
172  (fset 'notmuch-search-stash-map notmuch-search-stash-map)\r
173 @@ -235,6 +236,19 @@ For a mouse binding, return nil."\r
174    (interactive)\r
175    (notmuch-common-do-stash (notmuch-search-find-thread-id)))\r
176  \r
177 +(defun notmuch-search-stash-msgids ()\r
178 +  "Copy all Message-ID's in currently selected thread(s) to kill-ring."\r
179 +  (interactive)\r
180 +  (save-excursion\r
181 +    (if (region-active-p)\r
182 +        (let* ((beg (region-beginning))\r
183 +               (end (region-end)))\r
184 +          (notmuch-common-do-stash\r
185 +           (mapconcat 'identity\r
186 +                      (notmuch-search-find-msgids-region beg end)\r
187 +                      " or ")))\r
188 +      (notmuch-common-do-stash (notmuch-search-find-msgids)))))\r
189 +\r
190  (defvar notmuch-search-query-string)\r
191  (defvar notmuch-search-target-thread)\r
192  (defvar notmuch-search-target-line)\r
193 @@ -402,6 +416,14 @@ Complete list of currently available key bindings:\r
194    "Return a list of threads for the current region"\r
195    (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))\r
196  \r
197 +(defun notmuch-search-find-msgids ()\r
198 +  "Return all Message-Id's for the current thread"\r
199 +  (get-text-property (point) 'notmuch-search-msgids))\r
200 +\r
201 +(defun notmuch-search-find-msgids-region (beg end)\r
202 +  "Return a list of all Message-Id's for the threads in the current region"\r
203 +  (notmuch-search-properties-in-region 'notmuch-search-msgids beg end))\r
204 +\r
205  (defun notmuch-search-find-authors ()\r
206    "Return the authors for the current thread"\r
207    (get-text-property (point) 'notmuch-search-authors))\r
208 @@ -448,23 +470,6 @@ Complete list of currently available key bindings:\r
209    (let ((message-id (notmuch-search-find-thread-id)))\r
210      (notmuch-mua-new-reply message-id prompt-for-sender)))\r
211  \r
212 -(defun notmuch-call-notmuch-process (&rest args)\r
213 -  "Synchronously invoke \"notmuch\" with the given list of arguments.\r
214 -\r
215 -Output from the process will be presented to the user as an error\r
216 -and will also appear in a buffer named \"*Notmuch errors*\"."\r
217 -  (let ((error-buffer (get-buffer-create "*Notmuch errors*")))\r
218 -    (with-current-buffer error-buffer\r
219 -       (erase-buffer))\r
220 -    (if (eq (apply 'call-process notmuch-command nil error-buffer nil args) 0)\r
221 -       (point)\r
222 -      (progn\r
223 -       (with-current-buffer error-buffer\r
224 -         (let ((beg (point-min))\r
225 -               (end (- (point-max) 1)))\r
226 -           (error (buffer-substring beg end))\r
227 -           ))))))\r
228 -\r
229  (defun notmuch-tag (query &rest tags)\r
230    "Add/remove tags in TAGS to messages matching QUERY.\r
231  \r
232 @@ -476,8 +481,32 @@ messages instead of running (notmuch-call-notmuch-process \"tag\" ..)\r
233  directly, so that hooks specified in notmuch-before-tag-hook and\r
234  notmuch-after-tag-hook will be run."\r
235    (run-hooks 'notmuch-before-tag-hook)\r
236 -  (apply 'notmuch-call-notmuch-process\r
237 -        (append (list "tag") tags (list "--" query)))\r
238 +\r
239 +  (let ((query-buffer (get-buffer-create "*Notmuch query*"))\r
240 +        (error-buffer (get-buffer-create "*Notmuch errors*")))\r
241 +    (with-current-buffer error-buffer\r
242 +       (erase-buffer))\r
243 +\r
244 +    (with-current-buffer query-buffer\r
245 +        (erase-buffer)\r
246 +        (insert query)\r
247 +\r
248 +    (if (eq\r
249 +        (apply 'call-process-region\r
250 +               (append\r
251 +                (list (point-min) (point-max) notmuch-command nil error-buffer nil)\r
252 +                (list "tag" "--stdin") tags))\r
253 +        0)\r
254 +       (point)\r
255 +      (progn\r
256 +       (with-current-buffer error-buffer\r
257 +         (let ((beg (point-min))\r
258 +               (end (- (point-max) 1)))\r
259 +           (error (buffer-substring beg end))\r
260 +           )))))\r
261 +\r
262 +    (kill-buffer query-buffer))\r
263 +\r
264    (run-hooks 'notmuch-after-tag-hook))\r
265  \r
266  (defcustom notmuch-before-tag-hook nil\r
267 @@ -541,7 +570,7 @@ the messages that were tagged"\r
268    (notmuch-search-add-tag-region tag (point) (point)))\r
269  \r
270  (defun notmuch-search-add-tag-region (tag beg end)\r
271 -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))\r
272 +  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-msgids-region beg end) " or ")))\r
273      (notmuch-tag search-id-string (concat "+" tag))\r
274      (save-excursion\r
275        (let ((last-line (line-number-at-pos end))\r
276 @@ -555,7 +584,7 @@ the messages that were tagged"\r
277    (notmuch-search-remove-tag-region tag (point) (point)))\r
278  \r
279  (defun notmuch-search-remove-tag-region (tag beg end)\r
280 -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))\r
281 +  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-msgids-region beg end) " or ")))\r
282      (notmuch-tag search-id-string (concat "-" tag))\r
283      (save-excursion\r
284        (let ((last-line (line-number-at-pos end))\r
285 @@ -589,9 +618,9 @@ thread or threads in the current region."\r
286           "Tag to remove: "\r
287           (if (region-active-p)\r
288               (mapconcat 'identity\r
289 -                        (notmuch-search-find-thread-id-region (region-beginning) (region-end))\r
290 +                        (notmuch-search-find-msgids-region (region-beginning) (region-end))\r
291                          " ")\r
292 -           (notmuch-search-find-thread-id)))))\r
293 +           (notmuch-search-find-msgids)))))\r
294    (save-excursion\r
295      (if (region-active-p)\r
296         (let* ((beg (region-beginning))\r
297 @@ -801,13 +830,14 @@ non-authors is found, assume that all of the authors match."\r
298               (while more\r
299                 (while (and (< line (length string)) (= (elt string line) ?\n))\r
300                   (setq line (1+ line)))\r
301 -               (if (string-match "^\\(thread:[0-9A-Fa-f]*\\) \\([^][]*\\) \\(\\[[0-9/]*\\]\\) \\([^;]*\\); \\(.*\\) (\\([^()]*\\))$" string line)\r
302 +               (if (string-match "^\\(thread:[0-9A-Fa-f]*\\) \\([^][]*\\) \\(\\[[0-9/]*\\]\\) \\([^;]*\\); \\(.*\\) (\\([^()]*\\)) \\((.*\\(or.*\\)*\\)$" string line)\r
303                     (let* ((thread-id (match-string 1 string))\r
304                            (date (match-string 2 string))\r
305                            (count (match-string 3 string))\r
306                            (authors (match-string 4 string))\r
307                            (subject (match-string 5 string))\r
308                            (tags (match-string 6 string))\r
309 +                          (msgids (match-string 7 string))\r
310                            (tag-list (if tags (save-match-data (split-string tags)))))\r
311                       (goto-char (point-max))\r
312                       (if (/= (match-beginning 1) line)\r
313 @@ -816,6 +846,7 @@ non-authors is found, assume that all of the authors match."\r
314                         (notmuch-search-show-result date count authors subject tags)\r
315                         (notmuch-search-color-line beg (point-marker) tag-list)\r
316                         (put-text-property beg (point-marker) 'notmuch-search-thread-id thread-id)\r
317 +                       (put-text-property beg (point-marker) 'notmuch-search-msgids msgids)\r
318                         (put-text-property beg (point-marker) 'notmuch-search-authors authors)\r
319                         (put-text-property beg (point-marker) 'notmuch-search-subject subject)\r
320                         (if (string= thread-id notmuch-search-target-thread)\r
321 @@ -834,10 +865,10 @@ non-authors is found, assume that all of the authors match."\r
322        (delete-process proc))))\r
323  \r
324  (defun notmuch-search-operate-all (action)\r
325 -  "Add/remove tags from all matching messages.\r
326 +  "Add/remove tags to/from all threads in current search buffer.\r
327  \r
328 -This command adds or removes tags from all messages matching the\r
329 -current search terms. When called interactively, this command\r
330 +This command adds or removes tags from all threads displayed in\r
331 +the current search buffer. When called interactively, this command\r
332  will prompt for tags to be added or removed. Tags prefixed with\r
333  '+' will be added and tags prefixed with '-' will be removed.\r
334  \r
335 @@ -845,7 +876,10 @@ Each character of the tag name may consist of alphanumeric\r
336  characters as well as `_.+-'.\r
337  "\r
338    (interactive "sOperation (+add -drop): notmuch tag ")\r
339 -  (let ((action-split (split-string action " +")))\r
340 +  (let ((action-split (split-string action " +"))\r
341 +        (msgids (mapconcat 'identity\r
342 +                           (notmuch-search-find-msgids-region (point-min) (- (point-max) 2))\r
343 +                           " or ")))\r
344      ;; Perform some validation\r
345      (let ((words action-split))\r
346        (when (null words) (error "No operation given"))\r
347 @@ -853,7 +887,7 @@ characters as well as `_.+-'.\r
348         (unless (string-match-p "^[-+][-+_.[:word:]]+$" (car words))\r
349           (error "Action must be of the form `+thistag -that_tag'"))\r
350         (setq words (cdr words))))\r
351 -    (apply 'notmuch-tag notmuch-search-query-string action-split)))\r
352 +    (apply 'notmuch-tag msgids action-split)))\r
353  \r
354  (defun notmuch-search-buffer-title (query)\r
355    "Returns the title for a buffer with notmuch search results."\r
356 @@ -913,6 +947,7 @@ The optional parameters are used as follows:\r
357         (let ((proc (start-process\r
358                      "notmuch-search" buffer\r
359                      notmuch-command "search"\r
360 +                    "--output=summary-ids"\r
361                      (if oldest-first\r
362                          "--sort=oldest-first"\r
363                        "--sort=newest-first")\r
364 diff --git a/notmuch-search.c b/notmuch-search.c\r
365 index 2288eb7..b3af88b 100644\r
366 --- a/notmuch-search.c\r
367 +++ b/notmuch-search.c\r
368 @@ -22,6 +22,7 @@\r
369  \r
370  typedef enum {\r
371      OUTPUT_SUMMARY,\r
372 +    OUTPUT_SUMMARY_IDS,\r
373      OUTPUT_THREADS,\r
374      OUTPUT_MESSAGES,\r
375      OUTPUT_FILES,\r
376 @@ -274,7 +275,7 @@ do_search_threads (const search_format_t *format,\r
377  \r
378             fputs (format->tag_end, stdout);\r
379  \r
380 -           if (format == &format_text) {\r
381 +           if (format == &format_text && output == OUTPUT_SUMMARY_IDS) {\r
382                 notmuch_messages_t *toplevel;\r
383                 const char *first;\r
384  \r
385 @@ -462,6 +463,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
386             opt = argv[i] + sizeof ("--output=") - 1;\r
387             if (strcmp (opt, "summary") == 0) {\r
388                 output = OUTPUT_SUMMARY;\r
389 +           } else if (strcmp (opt, "summary-ids") == 0) {\r
390 +               output = OUTPUT_SUMMARY_IDS;\r
391             } else if (strcmp (opt, "threads") == 0) {\r
392                 output = OUTPUT_THREADS;\r
393             } else if (strcmp (opt, "messages") == 0) {\r
394 @@ -513,6 +516,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
395      switch (output) {\r
396      default:\r
397      case OUTPUT_SUMMARY:\r
398 +    case OUTPUT_SUMMARY_IDS:\r
399      case OUTPUT_THREADS:\r
400         ret = do_search_threads (format, query, sort, output);\r
401         break;\r
402 diff --git a/test/emacs b/test/emacs\r
403 index 53f455a..6479c4e 100755\r
404 --- a/test/emacs\r
405 +++ b/test/emacs\r
406 @@ -239,7 +239,7 @@ Subject:\r
407  EOF\r
408  test_expect_equal_file OUTPUT EXPECTED\r
409  \r
410 -test_begin_subtest "Reply within emacs"\r
411 +test_begin_subtest "Compose reply in emacs"\r
412  test_emacs '(notmuch-search "subject:\"testing message sent via SMTP\"")\r
413             (notmuch-test-wait)\r
414             (notmuch-search-reply-to-thread)\r
415 @@ -257,6 +257,53 @@ On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> w\r
416  EOF\r
417  test_expect_equal_file OUTPUT EXPECTED\r
418  \r
419 +test_begin_subtest "Send reply from within Emacs"\r
420 +$TEST_DIRECTORY/smtp-dummy sent_message &\r
421 +smtp_dummy_pid=$!\r
422 +test_emacs \\r
423 +'(let ((message-send-mail-function '\''message-smtpmail-send-it)\r
424 +       (smtpmail-smtp-server "localhost")\r
425 +       (smtpmail-smtp-service "25025"))\r
426 +  (notmuch-search "subject:\"testing message sent via SMTP\"")\r
427 +  (notmuch-test-wait)\r
428 +  (notmuch-search-reply-to-thread)\r
429 +  (message-goto-to)\r
430 +  (message-goto-body)\r
431 +  (end-of-buffer)\r
432 +  (newline)\r
433 +  (insert "Reply to a message via Emacs with fake SMTP")\r
434 +  (message-send-and-exit))' >/dev/null 2>&1\r
435 +wait ${smtp_dummy_pid}\r
436 +notmuch new >/dev/null\r
437 +sed \\r
438 +    -e s',^User-Agent: Notmuch/.* Emacs/.*,User-Agent: Notmuch/XXX Emacs/XXX,' \\r
439 +    -e s',^Message-ID: <.*>$,Message-ID: <XXX>,' \\r
440 +    -e s',^In-Reply-To: <.*>$,In-Reply-To: <XXX>,' \\r
441 +    -e s',^References: <.*>$,References: <XXX>,' \\r
442 +    -e s',^Date: .*$,Date: Fri\, 29 Mar 1974 10:05:00 -0000,' < sent_message >OUTPUT\r
443 +cat <<EOF >EXPECTED\r
444 +From: Notmuch Test Suite <test_suite@notmuchmail.org>\r
445 +To: user@example.com\r
446 +Subject: Re: Testing message sent via SMTP\r
447 +In-Reply-To: <XXX>\r
448 +References: <XXX>\r
449 +User-Agent: Notmuch/XXX Emacs/XXX\r
450 +Date: Fri, 29 Mar 1974 10:05:00 -0000\r
451 +Message-ID: <XXX>\r
452 +MIME-Version: 1.0\r
453 +Content-Type: text/plain; charset=us-ascii\r
454 +\r
455 +On 01 Jan 2000 12:00:00 -0000, Notmuch Test Suite <test_suite@notmuchmail.org> wrote:\r
456 +> This is a test that messages are sent via SMTP\r
457 +\r
458 +Reply to a message via Emacs with fake SMTP\r
459 +EOF\r
460 +test_expect_equal_file OUTPUT EXPECTED\r
461 +\r
462 +test_begin_subtest "Verify that 'replied' tag is added to reply's parent message."\r
463 +output=$(notmuch search 'tag:replied' | notmuch_search_sanitize)\r
464 +test_expect_equal "$output" "thread:XXX   2000-01-01 [1/2] Notmuch Test Suite; Testing message sent via SMTP (inbox replied)"\r
465 +\r
466  test_begin_subtest "Save attachment from within emacs using notmuch-show-save-attachments"\r
467  # save as archive to test that Emacs does not re-compress .gz\r
468  test_emacs '(let ((standard-input "\"attachment1.gz\""))\r
469 diff --git a/test/emacs-search-operate-all b/test/emacs-search-operate-all\r
470 new file mode 100755\r
471 index 0000000..48326c8\r
472 --- /dev/null\r
473 +++ b/test/emacs-search-operate-all\r
474 @@ -0,0 +1,29 @@\r
475 +#!/usr/bin/env bash\r
476 +\r
477 +test_description="emacs interface"\r
478 +. test-lib.sh\r
479 +\r
480 +EXPECTED=$TEST_DIRECTORY/emacs.expected-output\r
481 +\r
482 +add_email_corpus\r
483 +\r
484 +test_begin_subtest "Add/remove tags to/from all matching threads."\r
485 +test_emacs '(notmuch-search "tag:inbox AND tags")\r
486 +           (notmuch-test-wait)\r
487 +           (notmuch-search-operate-all "+matching -inbox")\r
488 +           (notmuch-search "tag:matching AND NOT tag:inbox")\r
489 +           (notmuch-test-wait)\r
490 +           (test-output)'\r
491 +cat <<EOF >EXPECTED\r
492 +  2009-11-18 [2/2]   Ingmar Vanhassel, Carl Worth  [notmuch] [PATCH] Typsos (matching unread)\r
493 +  2009-11-18 [3/3]   Adrian Perez de Castro, Keith Packard, Carl Worth  [notmuch] Introducing myself (matching signed unread)\r
494 +  2009-11-18 [3/3]   Israel Herraiz, Keith Packard, Carl Worth   [notmuch] New to the list (matching unread)\r
495 +  2009-11-18 [2/2]   Keith Packard, Carl Worth    [notmuch] [PATCH] Make notmuch-show 'X' (and 'x') commands remove inbox (and unread) tags (matching unread)\r
496 +  2009-11-18 [2/2]   Keith Packard, Alexander Botero-Lowry    [notmuch] [PATCH] Create a default notmuch-show-hook that highlights URLs and uses word-wrap (matching unread)\r
497 +  2009-11-18 [1/1]   Jan Janak            [notmuch] [PATCH] notmuch new: Support for conversion of spool subdirectories into tags (matching unread)\r
498 +  2009-11-18 [1/1]   Stewart Smith        [notmuch] [PATCH] Fix linking with gcc to use g++ to link in C++ libs. (matching unread)\r
499 +End of search results.\r
500 +EOF\r
501 +test_expect_equal_file OUTPUT EXPECTED\r
502 +\r
503 +test_done\r
504 diff --git a/test/notmuch-test b/test/notmuch-test\r
505 index 79e6267..bafbcb1 100755\r
506 --- a/test/notmuch-test\r
507 +++ b/test/notmuch-test\r
508 @@ -38,6 +38,7 @@ TESTS="\r
509    encoding\r
510    emacs\r
511    emacs-large-search-buffer\r
512 +  emacs-search-operate-all\r
513    maildir-sync\r
514    crypto\r
515    symbol-hiding\r
516 -- \r
517 1.7.5.4\r
518 \r