[PATCH 2/2] Add notmuch_database_reopen method
[notmuch-archives.git] / 17 / d9eb95d914e2e3ef73a6ebecc7db574454be27
1 Return-Path: <dmitry.kurochkin@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 E33A7431E64\r
6         for <notmuch@notmuchmail.org>; Sun, 29 Jan 2012 21:12:09 -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.799\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5\r
12         tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
13         FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] 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 CFbp6uBtzc-a for <notmuch@notmuchmail.org>;\r
17         Sun, 29 Jan 2012 21:12:08 -0800 (PST)\r
18 Received: from mail-bk0-f53.google.com (mail-bk0-f53.google.com\r
19         [209.85.214.53]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id 83573431FBC\r
22         for <notmuch@notmuchmail.org>; Sun, 29 Jan 2012 21:12:08 -0800 (PST)\r
23 Received: by bke11 with SMTP id 11so1040717bke.26\r
24         for <notmuch@notmuchmail.org>; Sun, 29 Jan 2012 21:12:07 -0800 (PST)\r
25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma;\r
26         h=from:to:cc:subject:in-reply-to:references:user-agent:date\r
27         :message-id:mime-version:content-type;\r
28         bh=0+tF/aLOanv2oh9WlNPT7MiK2smydsLKLfrBqnAXfGg=;\r
29         b=cW2pYoZJcTXtjTQLSkEHpUH8CNUOIa88Ci01x9NM43wlIHzqr1OQ0/IA3AZTDovSsw\r
30         oWMTQF567Roxc3Umwb1PyH7OjBZgrWepOVpqtigauxt2kPmYJLvsWGrVD1bmHBjsdG65\r
31         UYQqZaNSDrZ9/iVeTZ4oXKv48KSYkMGSJ/8GQ=\r
32 Received: by 10.204.156.204 with SMTP id y12mr7824088bkw.113.1327900326805;\r
33         Sun, 29 Jan 2012 21:12:06 -0800 (PST)\r
34 Received: from localhost ([91.144.186.21])\r
35         by mx.google.com with ESMTPS id x20sm19815794bka.9.2012.01.29.21.12.05\r
36         (version=TLSv1/SSLv3 cipher=OTHER);\r
37         Sun, 29 Jan 2012 21:12:06 -0800 (PST)\r
38 From: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>\r
39 To: Austin Clements <amdragon@MIT.EDU>\r
40 Subject: Re: [PATCH v2 03/13] emacs: make "+" and "-" tagging operations in\r
41         notmuch-search more robust\r
42 In-Reply-To: <20120130044806.GM17991@mit.edu>\r
43 References: <1327725684-5887-1-git-send-email-dmitry.kurochkin@gmail.com>\r
44         <1327890382-548-1-git-send-email-dmitry.kurochkin@gmail.com>\r
45         <1327890382-548-4-git-send-email-dmitry.kurochkin@gmail.com>\r
46         <20120130044806.GM17991@mit.edu>\r
47 User-Agent: Notmuch/0.11+139~gd9b7cab (http://notmuchmail.org) Emacs/23.3.1\r
48         (x86_64-pc-linux-gnu)\r
49 Date: Mon, 30 Jan 2012 09:10:56 +0400\r
50 Message-ID: <87pqe122sf.fsf@gmail.com>\r
51 MIME-Version: 1.0\r
52 Content-Type: text/plain; charset=us-ascii\r
53 Cc: notmuch@notmuchmail.org\r
54 X-BeenThere: notmuch@notmuchmail.org\r
55 X-Mailman-Version: 2.1.13\r
56 Precedence: list\r
57 List-Id: "Use and development of the notmuch mail system."\r
58         <notmuch.notmuchmail.org>\r
59 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
60         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
61 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
62 List-Post: <mailto:notmuch@notmuchmail.org>\r
63 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
64 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
65         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
66 X-List-Received-Date: Mon, 30 Jan 2012 05:12:10 -0000\r
67 \r
68 On Sun, 29 Jan 2012 23:48:06 -0500, Austin Clements <amdragon@MIT.EDU> wrote:\r
69 > Looking good.  Just a few small points below.\r
70\r
71 > Quoth Dmitry Kurochkin on Jan 30 at  6:26 am:\r
72 > > Before the change, "+" and "-" tagging operations in notmuch-search\r
73 > > view accepted only a single tag.  The patch makes them use the\r
74 > > recently added `notmuch-read-tag-changes' function (renamed\r
75 > > `notmuch-select-tags-with-completion'), which allows to enter multiple\r
76 > > tags with "+" and "-" prefixes.  So after the change, "+" and "-"\r
77 > > bindings in notmuch-search view allow to both add and remove multiple\r
78 > > tags.  The only difference between "+" and "-" is the minibuffer\r
79 > > initial input ("+" and "-" respectively).\r
80 > > ---\r
81 > >  emacs/notmuch.el |  164 +++++++++++++++++++++++++++---------------------------\r
82 > >  1 files changed, 82 insertions(+), 82 deletions(-)\r
83 > > \r
84 > > diff --git a/emacs/notmuch.el b/emacs/notmuch.el\r
85 > > index ff46617..90b594c 100644\r
86 > > --- a/emacs/notmuch.el\r
87 > > +++ b/emacs/notmuch.el\r
88 > > @@ -76,38 +76,57 @@ For example:\r
89 > >  (defvar notmuch-query-history nil\r
90 > >    "Variable to store minibuffer history for notmuch queries")\r
91 > >  \r
92 > > -(defun notmuch-tag-completions (&optional prefixes search-terms)\r
93 > > -  (let ((tag-list\r
94 > > -    (split-string\r
95 > > -     (with-output-to-string\r
96 > > -       (with-current-buffer standard-output\r
97 > > -         (apply 'call-process notmuch-command nil t\r
98 > > -                nil "search-tags" search-terms)))\r
99 > > -     "\n+" t)))\r
100 > > -    (if (null prefixes)\r
101 > > -   tag-list\r
102 > > -      (apply #'append\r
103 > > -        (mapcar (lambda (tag)\r
104 > > -                  (mapcar (lambda (prefix)\r
105 > > -                            (concat prefix tag)) prefixes))\r
106 > > -                tag-list)))))\r
107 > > +(defun notmuch-tag-completions (&optional search-terms)\r
108 > > +  (split-string\r
109 > > +   (with-output-to-string\r
110 > > +     (with-current-buffer standard-output\r
111 > > +       (apply 'call-process notmuch-command nil t\r
112 > > +         nil "search-tags" search-terms)))\r
113 > > +   "\n+" t))\r
114 > >  \r
115 > >  (defun notmuch-select-tag-with-completion (prompt &rest search-terms)\r
116 > > -  (let ((tag-list (notmuch-tag-completions nil search-terms)))\r
117 > > +  (let ((tag-list (notmuch-tag-completions search-terms)))\r
118 > >      (completing-read prompt tag-list)))\r
119 > >  \r
120 > > -(defun notmuch-select-tags-with-completion (prompt &optional prefixes &rest search-terms)\r
121 > > -  (let ((tag-list (notmuch-tag-completions prefixes search-terms))\r
122 > > -   (crm-separator " ")\r
123 > > -   ;; By default, space is bound to "complete word" function.\r
124 > > -   ;; Re-bind it to insert a space instead.  Note that <tab>\r
125 > > -   ;; still does the completion.\r
126 > > -   (crm-local-completion-map\r
127 > > -    (let ((map (make-sparse-keymap)))\r
128 > > -      (set-keymap-parent map crm-local-completion-map)\r
129 > > -      (define-key map " " 'self-insert-command)\r
130 > > -      map)))\r
131 > > -    (delete "" (completing-read-multiple prompt tag-list))))\r
132 > > +(defun notmuch-read-tag-changes (&optional initial-input &rest search-terms)\r
133 > > +  (let* ((all-tag-list (notmuch-tag-completions))\r
134 > > +    (add-tag-list (mapcar (apply-partially 'concat "+") all-tag-list))\r
135 > > +    (remove-tag-list (mapcar (apply-partially 'concat "-")\r
136 > > +                             (if (null search-terms)\r
137 > > +                                 all-tag-list\r
138 > > +                               (notmuch-tag-completions search-terms))))\r
139 > > +    (tag-list (append add-tag-list remove-tag-list))\r
140 > > +    (crm-separator " ")\r
141 > > +    ;; By default, space is bound to "complete word" function.\r
142 > > +    ;; Re-bind it to insert a space instead.  Note that <tab>\r
143 > > +    ;; still does the completion.\r
144 > > +    (crm-local-completion-map\r
145 > > +     (let ((map (make-sparse-keymap)))\r
146 > > +       (set-keymap-parent map crm-local-completion-map)\r
147 > > +       (define-key map " " 'self-insert-command)\r
148 > > +       map)))\r
149 > > +    (delete "" (completing-read-multiple "Tags (+add -drop): "\r
150 > > +           tag-list nil nil initial-input))))\r
151 > > +\r
152 > > +(defun notmuch-update-tags (tags tag-changes)\r
153 > > +  "Return a copy of TAGS with additions and removals from TAG-CHANGES.\r
154 > > +\r
155 > > +TAG-CHANGES must be a list of tags names, each prefixed with\r
156 > > +either a \"+\" to indicate the tag should be added to TAGS if not\r
157 > > +present or a \"-\" to indicate that the tag should be removed\r
158 > > +from TAGS if present."\r
159 > > +  (let ((result-tags (copy-sequence tags)))\r
160 > > +    (dolist (tag-change tag-changes)\r
161 > > +      (unless (string= tag-change "")\r
162\r
163 > This function should give the "must be of the form" error for empty\r
164 > strings, rather than silently ignoring them.  It turns out\r
165 > `string-to-char' on an empty string is fine (it returns 0, which will\r
166 > trigger the error), but `substring' isn't.  Perhaps move the unless\r
167 > into the let before, like\r
168 >  (let ((op (string-to-char tag-change))\r
169 >        (tag (unless (string= tag-change "") (substring tag-change 1))))\r
170\r
171 \r
172 done\r
173 \r
174 > > +   (let ((op (string-to-char tag-change))\r
175 > > +         (tag (substring tag-change 1)))\r
176 > > +     (case op\r
177 > > +       (?+ (unless (member tag result-tags)\r
178 > > +             (push tag result-tags)))\r
179 > > +       (?- (setq result-tags (delete tag result-tags)))\r
180 > > +       (otherwise\r
181 > > +        (error "Changed tag must be of the form `+this_tag' or `-that_tag'"))))))\r
182 > > +    (sort result-tags 'string<)))\r
183 > >  \r
184 > >  (defun notmuch-foreach-mime-part (function mm-handle)\r
185 > >    (cond ((stringp (car mm-handle))\r
186 > > @@ -447,6 +466,10 @@ Complete list of currently available key bindings:\r
187 > >    "Return a list of threads for the current region"\r
188 > >    (notmuch-search-properties-in-region 'notmuch-search-thread-id beg end))\r
189 > >  \r
190 > > +(defun notmuch-search-find-thread-id-region-search (beg end)\r
191 > > +  "Return a search string for threads for the current region"\r
192 > > +  (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))\r
193 > > +\r
194 > >  (defun notmuch-search-find-authors ()\r
195 > >    "Return the authors for the current thread"\r
196 > >    (get-text-property (point) 'notmuch-search-authors))\r
197 > > @@ -590,74 +613,53 @@ the messages that were tagged"\r
198 > >     (forward-line 1))\r
199 > >        output)))\r
200 > >  \r
201 > > -(defun notmuch-search-add-tag-thread (tag)\r
202 > > -  (notmuch-search-add-tag-region tag (point) (point)))\r
203 > > +(defun notmuch-search-tag-thread (&rest tags)\r
204\r
205 > Maybe "tag-changes" instead of "tags" for this and\r
206 > notmuch-search-tag-region?\r
207\r
208 \r
209 This should also be changed in `notmuch-search-tag-all' and\r
210 `notmuch-tag' (which involved docstring changes), so I will do this in a\r
211 separate patch.\r
212 \r
213 Regards,\r
214   Dmitry\r
215 \r
216 > > +  "Change tags for the currently selected thread.\r
217 > >  \r
218 > > -(defun notmuch-search-add-tag-region (tag beg end)\r
219 > > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))\r
220 > > -    (notmuch-tag search-id-string (concat "+" tag))\r
221 > > -    (save-excursion\r
222 > > -      (let ((last-line (line-number-at-pos end))\r
223 > > -       (max-line (- (line-number-at-pos (point-max)) 2)))\r
224 > > -   (goto-char beg)\r
225 > > -   (while (<= (line-number-at-pos) (min last-line max-line))\r
226 > > -     (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))\r
227 > > -     (forward-line))))))\r
228 > > +See `notmuch-search-tag-region' for details."\r
229 > > +  (apply 'notmuch-search-tag-region (point) (point) tags))\r
230 > >  \r
231 > > -(defun notmuch-search-remove-tag-thread (tag)\r
232 > > -  (notmuch-search-remove-tag-region tag (point) (point)))\r
233 > > +(defun notmuch-search-tag-region (beg end &rest tags)\r
234 > > +  "Change tags for threads in the given region.\r
235 > >  \r
236 > > -(defun notmuch-search-remove-tag-region (tag beg end)\r
237 > > -  (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or ")))\r
238 > > -    (notmuch-tag search-id-string (concat "-" tag))\r
239 > > +TAGS is a list of tag operations for `notmuch-tag'.  The tags are\r
240 > > +added or removed for all threads in the region from BEG to END."\r
241 > > +  (let ((search-string (notmuch-search-find-thread-id-region-search beg end)))\r
242 > > +    (apply 'notmuch-tag search-string tags)\r
243 > >      (save-excursion\r
244 > >        (let ((last-line (line-number-at-pos end))\r
245 > >         (max-line (- (line-number-at-pos (point-max)) 2)))\r
246 > >     (goto-char beg)\r
247 > >     (while (<= (line-number-at-pos) (min last-line max-line))\r
248 > > -     (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))\r
249 > > +     (notmuch-search-set-tags\r
250 > > +      (notmuch-update-tags (notmuch-search-get-tags) tags))\r
251 > >       (forward-line))))))\r
252 > >  \r
253 > > -(defun notmuch-search-add-tag (tag)\r
254 > > -  "Add a tag to the currently selected thread or region.\r
255 > > -\r
256 > > -The tag is added to all messages in the currently selected thread\r
257 > > -or threads in the current region."\r
258 > > -  (interactive\r
259 > > -   (list (notmuch-select-tag-with-completion "Tag to add: ")))\r
260 > > -  (save-excursion\r
261 > > -    (if (region-active-p)\r
262 > > -   (let* ((beg (region-beginning))\r
263 > > -          (end (region-end)))\r
264 > > -     (notmuch-search-add-tag-region tag beg end))\r
265 > > -      (notmuch-search-add-tag-thread tag))))\r
266 > > -\r
267 > > -(defun notmuch-search-remove-tag (tag)\r
268 > > -  "Remove a tag from the currently selected thread or region.\r
269\r
270 > It's great to see all of this old copy-pasted code go away!\r
271\r
272 > > +(defun notmuch-search-tag (&optional initial-input)\r
273 > > +  "Change tags for the currently selected thread or region."\r
274 > > +  (interactive)\r
275 > > +  (let* ((beg (if (region-active-p) (region-beginning) (point)))\r
276 > > +    (end (if (region-active-p) (region-end) (point)))\r
277 > > +    (search-string (notmuch-search-find-thread-id-region-search beg end))\r
278 > > +    (tags (notmuch-read-tag-changes initial-input search-string)))\r
279 > > +    (apply 'notmuch-search-tag-region beg end tags)))\r
280 > > +\r
281 > > +(defun notmuch-search-add-tag ()\r
282 > > +  "Same as `notmuch-search-tag' but sets initial input to '+'."\r
283 > > +  (interactive)\r
284 > > +  (notmuch-search-tag "+"))\r
285 > >  \r
286 > > -The tag is removed from all messages in the currently selected\r
287 > > -thread or threads in the current region."\r
288 > > -  (interactive\r
289 > > -   (list (notmuch-select-tag-with-completion\r
290 > > -     "Tag to remove: "\r
291 > > -     (if (region-active-p)\r
292 > > -         (mapconcat 'identity\r
293 > > -                    (notmuch-search-find-thread-id-region (region-beginning) (region-end))\r
294 > > -                    " ")\r
295 > > -       (notmuch-search-find-thread-id)))))\r
296 > > -  (save-excursion\r
297 > > -    (if (region-active-p)\r
298 > > -   (let* ((beg (region-beginning))\r
299 > > -          (end (region-end)))\r
300 > > -     (notmuch-search-remove-tag-region tag beg end))\r
301 > > -      (notmuch-search-remove-tag-thread tag))))\r
302 > > +(defun notmuch-search-remove-tag ()\r
303 > > +  "Same as `notmuch-search-tag' but sets initial input to '-'."\r
304 > > +  (interactive)\r
305 > > +  (notmuch-search-tag "-"))\r
306 > >  \r
307 > >  (defun notmuch-search-archive-thread ()\r
308 > >    "Archive the currently selected thread (remove its \"inbox\" tag).\r
309 > >  \r
310 > >  This function advances the next thread when finished."\r
311 > >    (interactive)\r
312 > > -  (notmuch-search-remove-tag-thread "inbox")\r
313 > > +  (notmuch-search-tag-thread "-inbox")\r
314 > >    (notmuch-search-next-thread))\r
315 > >  \r
316 > >  (defvar notmuch-search-process-filter-data nil\r
317 > > @@ -893,9 +895,7 @@ will prompt for tags to be added or removed. Tags prefixed with\r
318 > >  Each character of the tag name may consist of alphanumeric\r
319 > >  characters as well as `_.+-'.\r
320 > >  "\r
321 > > -  (interactive (notmuch-select-tags-with-completion\r
322 > > -           "Operations (+add -drop): notmuch tag "\r
323 > > -           '("+" "-")))\r
324 > > +  (interactive (notmuch-read-tag-changes))\r
325 > >    (apply 'notmuch-tag notmuch-search-query-string actions))\r
326 > >  \r
327 > >  (defun notmuch-search-buffer-title (query)\r