[PATCH v3 5/7] Introduce _notmuch_message_has_term()
[notmuch-archives.git] / 67 / 679bec311f3300324ce5399e308bc06cbb70f4
1 Return-Path: <daniel.schoepe@googlemail.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 68A55429E28\r
6         for <notmuch@notmuchmail.org>; Wed, 25 May 2011 14:22:08 -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.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 i1InsvSPNl+V for <notmuch@notmuchmail.org>;\r
17         Wed, 25 May 2011 14:22:07 -0700 (PDT)\r
18 Received: from mail-fx0-f53.google.com (mail-fx0-f53.google.com\r
19         [209.85.161.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 980E4431FB6\r
22         for <notmuch@notmuchmail.org>; Wed, 25 May 2011 14:22:06 -0700 (PDT)\r
23 Received: by fxm8 with SMTP id 8so172094fxm.26\r
24         for <notmuch@notmuchmail.org>; Wed, 25 May 2011 14:22:05 -0700 (PDT)\r
25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
26         d=googlemail.com; s=gamma;\r
27         h=domainkey-signature:from:to:cc:subject:in-reply-to:references\r
28         :user-agent:date:message-id:mime-version:content-type;\r
29         bh=lzyEBwCdKa8MXZUjegknZQ/EpJfpKDhkk3FWSgHqLqk=;\r
30         b=i/71VqNfVNuLnMDee6iYH+PGpFOjKSlXgrUuoKiW0ubQ0CnKp83N4MjlGZGL1mE4FO\r
31         KOZywn7jOPLk8Z8lc1hy7uLb06sclKkMCSdgiBQXj3gncq4qreE4dcUF/ggKAgeXlwKD\r
32         V4Buy69TrclUE6bK/9mu4DhTuNR7WOq5uS6iA=\r
33 DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma;\r
34         h=from:to:cc:subject:in-reply-to:references:user-agent:date\r
35         :message-id:mime-version:content-type;\r
36         b=ZRoTqkHfPRs+xlDs+1i5JbtJasxAwRP3lnMUWHiYcbJk3Msgl2uef5HM075u2OSHdH\r
37         5ZDWm0Kv1aBbeMnCuLqf+oqhdP8vx8rMS4O7eQxTMx3trlo0nMgOh8tBctHuyQ3+wR4P\r
38         cmiMDL2aZW7UnJJlnwHBpLndmM2h/mHtOsZmM=\r
39 Received: by 10.223.47.209 with SMTP id o17mr47209faf.129.1306358525226;\r
40         Wed, 25 May 2011 14:22:05 -0700 (PDT)\r
41 Received: from localhost (dslb-178-004-026-109.pools.arcor-ip.net\r
42         [178.4.26.109])\r
43         by mx.google.com with ESMTPS id l26sm15345fam.21.2011.05.25.14.22.02\r
44         (version=TLSv1/SSLv3 cipher=OTHER);\r
45         Wed, 25 May 2011 14:22:03 -0700 (PDT)\r
46 From: Daniel Schoepe <daniel.schoepe@googlemail.com>\r
47 To: Austin Clements <amdragon@mit.edu>\r
48 Subject: Re: [PATCH] emacs: Make the queries used in the all-tags section\r
49 In-Reply-To: <BANLkTikAB0mogUuS-nT_-i51LBdUBHCz3g@mail.gmail.com>\r
50 References: <87fwoath2s.fsf@gilead.home.box>\r
51         <BANLkTinKS5LbQsZuK8HyCzj+Lo4xqa2Sfg@mail.gmail.com>\r
52         <871uznqeox.fsf@tredergarh.home.box>\r
53         <BANLkTin0+O=mubHF7JNpw4u3DQDQJQ5zbw@mail.gmail.com>\r
54         <874o4iwwp5.fsf@gilead.invalid> <871uzmwtng.fsf@gilead.invalid>\r
55         <BANLkTikAB0mogUuS-nT_-i51LBdUBHCz3g@mail.gmail.com>\r
56 User-Agent: Notmuch/0.5-210-g1acc997 (http://notmuchmail.org) Emacs/23.3.1\r
57         (x86_64-pc-linux-gnu)\r
58 Date: Wed, 25 May 2011 23:21:54 +0200\r
59 Message-ID: <87ei3mcw7h.fsf@gilead.invalid>\r
60 MIME-Version: 1.0\r
61 Content-Type: multipart/signed; boundary="==-=-=";\r
62         micalg=pgp-sha1; protocol="application/pgp-signature"\r
63 Cc: notmuch@notmuchmail.org\r
64 X-BeenThere: notmuch@notmuchmail.org\r
65 X-Mailman-Version: 2.1.13\r
66 Precedence: list\r
67 List-Id: "Use and development of the notmuch mail system."\r
68         <notmuch.notmuchmail.org>\r
69 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
70         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
71 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
72 List-Post: <mailto:notmuch@notmuchmail.org>\r
73 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
74 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
75         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
76 X-List-Received-Date: Wed, 25 May 2011 21:22:08 -0000\r
77 \r
78 --==-=-=\r
79 Content-Type: multipart/mixed; boundary="=-=-="\r
80 \r
81 --=-=-=\r
82 Content-Type: text/plain\r
83 Content-Transfer-Encoding: quoted-printable\r
84 \r
85 On Wed, 25 May 2011 15:11:16 -0400, Austin Clements <amdragon@mit.edu> wrot=\r
86 e:\r
87 > At least in Emacs 23.3.1, it has to be (const :tag "tag:TAG" nil).  I\r
88 > didn't think the order mattered, but the tag didn't display otherwise.\r
89 >  It would also be good to give descriptive tags to the other choices.\r
90 >=20\r
91 > It would be more consistent if the function form of this also returned\r
92 > a filter expression, rather than a whole expression.  This also\r
93 > simplifies the documentation.\r
94 \r
95 Thanks for the suggestions. (At first, I wanted to allow the user\r
96 to be able to also include messages that don't have that tag, but this\r
97 really no longer belongs in the all tags-section).\r
98 \r
99 > So, perhaps something like\r
100 >\r
101 > (defcustom notmuch-hello-tag-list-counts nil\r
102 >   "Method for generating counts displayed in the all tags list.\r
103 >=20\r
104 > This variable controls the query used to generate counts for each\r
105 > tag in the \"all tags\" list.  If nil, the tag list will count\r
106 > all messages with each tag.  This can be a query string that will\r
107 > filter the messages counted for each tag.  Finally, this can be a\r
108 > function that will be called for each tag and should return a\r
109 > filter query for that tag, or nil to hide the tag."\r
110 >   :type '(choice (const :tag "Count all messages" nil)\r
111 >                  (const :tag "Count unread messages" "tag:unread")\r
112 >                  (const :tag "Custom filter" string)\r
113 >                  (const :tag "Custom filter function" function))\r
114 >   :group 'notmuch)\r
115 \r
116 That is slightly less accurate though, since the query is not only used\r
117 to generate the counts, but also the searches that are performed when\r
118 one presses return on a tag in the list.\r
119 \r
120 > > +(defun notmuch-hello-generate-tag-alist ()\r
121 > > +  "Return an alist from tags to queries to display in the all-tags sec=\r
122 tion."\r
123 > > +  (notmuch-filter\r
124 > > +   'cdr\r
125 > > +   (mapcar '(lambda (tag)\r
126 >=20\r
127 > You don't need the quote before a lambda form.  (You can also change\r
128 > 'cdr to #'cdr to further hint the compiler, though it appears to not\r
129 > matter in this case.)\r
130 \r
131 Oh, yeah, normally I'm aware of that, don't know what made me quote it\r
132 at the time I wrote it.\r
133 \r
134 > > +(defun notmuch-filter (pred lst)\r
135 > > +  "Return a list containing all elements from LST that satisfy PRED."\r
136 >=20\r
137 > notmuch-remove-if-not would be more canonical (yeah, it's unwieldy,\r
138 > blame Common Lisp).  Also, since Elisp doesn't do tail-recursion, the\r
139 > standard way to define a remove-if-not function is\r
140 >=20\r
141 > (defun notmuch-remove-if-not (predicate list)\r
142 >   "Return a copy of LIST with all items not satisfying PREDICATE removed."\r
143 >   (let (out)\r
144 >     (while list\r
145 >       (when (funcall predicate (car list))\r
146 >         (push (car list) out))\r
147 >       (setq list (cdr list)))\r
148 >     (nreverse out)))\r
149 >=20\r
150 > (Why oh why Elisp hasn't just made remove-if and remove-if-not\r
151 > standard I don't know; they're redefined all over the Elisp code base.\r
152 >  Any everybody's afraid to use cl-seq's remove-if-not because it's so\r
153 > ridiculously complicated.)\r
154 \r
155 Ah, thanks. I guess too much exposure to Haskell (and how smart GHC is)\r
156 makes me write things in a functional style without thinking about\r
157 performance.\r
158 \r
159 I incorporated most of you recommendations in the attached patch.\r
160 \r
161 --=-=-=\r
162 Content-Type: text/x-diff\r
163 Content-Disposition: inline;\r
164  filename=0001-emacs-Make-queries-used-in-the-all-tags-section-conf.patch\r
165 Content-Transfer-Encoding: quoted-printable\r
166 \r
167 From=202056a455cdec6b980426552b8dcd7055f6cd0805 Mon Sep 17 00:00:00 2001\r
168 From: Daniel Schoepe <daniel.schoepe@googlemail.com>\r
169 Date: Fri, 20 May 2011 00:53:50 +0200\r
170 Subject: [PATCH] emacs: Make queries used in the all-tags section\r
171  configurable\r
172 \r
173 This patch adds a customization variable that controls what queries\r
174 are used to construct the all-tags section in notmuch-hello. It allows\r
175 the user to specify a function to construct the query given a tag or\r
176 a string that is used as a filter for each tag.\r
177 It also adds a variable to hide various tags from the all-tags section.\r
178 \r
179 Signed-off-by: Daniel Schoepe <daniel.schoepe@googlemail.com>\r
180 =2D--\r
181  emacs/notmuch-hello.el |   43 ++++++++++++++++++++++++++++++++++++++++---\r
182  emacs/notmuch-lib.el   |    9 +++++++++\r
183  2 files changed, 49 insertions(+), 3 deletions(-)\r
184 \r
185 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el\r
186 index e58dd24..bd95849 100644\r
187 =2D-- a/emacs/notmuch-hello.el\r
188 +++ b/emacs/notmuch-hello.el\r
189 @@ -55,6 +55,26 @@\r
190    :type 'boolean\r
191    :group 'notmuch)\r
192 =20\r
193 +(defcustom notmuch-hello-tag-list-make-query nil\r
194 +  "Function or string to generate queries for the all tags list.\r
195 +\r
196 +This variable controls which query results are shown for each tag\r
197 +in the \"all tags\" list. If nil, it will use all messages with\r
198 +that tag. If this is set to a string, it is used as a filter for\r
199 +messages having that tag (equivalent to \"tag:TAG and (THIS-VARIABLE)\").\r
200 +Finally this can be a function that will be called for each tag and\r
201 +should return a filter for that tag, or nil to hide the tag."\r
202 +  :type '(choice (const :tag "All messages" nil)\r
203 +                (const :tag "Unread messages" "tag:unread")\r
204 +                (const :tag "Custom filter" string)\r
205 +                (const :tag "Custom filter function" function))\r
206 +  :group 'notmuch)\r
207 +\r
208 +(defcustom notmuch-hello-hide-tags nil\r
209 +  "List of tags to be hidden in the \"all tags\"-section."\r
210 +  :type '(repeat string)\r
211 +  :group 'notmuch)\r
212 +\r
213  (defface notmuch-hello-logo-background\r
214    '((((class color)\r
215        (background dark))\r
216 @@ -318,6 +338,25 @@ Complete list of currently available key bindings:\r
217   ;;(setq buffer-read-only t)\r
218  )\r
219 =20\r
220 +(defun notmuch-hello-generate-tag-alist ()\r
221 +  "Return an alist from tags to queries to display in the all-tags section=\r
222 ."\r
223 +  (notmuch-remove-if-not\r
224 +   #'cdr\r
225 +   (mapcar (lambda (tag)\r
226 +            (cons tag\r
227 +                  (cond\r
228 +                   ((functionp notmuch-hello-tag-list-make-query)\r
229 +                    (concat "tag:" tag " and ("\r
230 +                            (funcall notmuch-hello-tag-list-make-query tag) ")"))\r
231 +                   ((stringp notmuch-hello-tag-list-make-query)\r
232 +                    (concat "tag:" tag " and ("\r
233 +                            notmuch-hello-tag-list-make-query ")"))\r
234 +                   (t (concat "tag:" tag)))))\r
235 +          (notmuch-remove-if-not\r
236 +           (lambda (tag)\r
237 +             (not (member tag notmuch-hello-hide-tags)))\r
238 +           (process-lines notmuch-command "search-tags")))))\r
239 +\r
240  ;;;###autoload\r
241  (defun notmuch-hello (&optional no-display)\r
242    "Run notmuch and display saved searches, known tags, etc."\r
243 @@ -396,9 +435,7 @@ Complete list of currently available key bindings:\r
244                       if (> (string-to-number (notmuch-saved-search-count (cdr elem))) 0)\r
245                       collect elem)))\r
246              (saved-widest (notmuch-hello-longest-label saved-alist))\r
247 =2D          (alltags-alist (if notmuch-show-all-tags-list\r
248 =2D                             (mapcar '(lambda (tag) (cons tag (concat "tag:" tag)))\r
249 =2D                                     (process-lines notmuch-command "search-tags"))))\r
250 +            (alltags-alist (if notmuch-show-all-tags-list (notmuch-hello-generat=\r
251 e-tag-alist)))\r
252              (alltags-widest (notmuch-hello-longest-label alltags-alist))\r
253              (widest (max saved-widest alltags-widest)))\r
254 =20\r
255 diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el\r
256 index cc80fb2..d5ca0f4 100644\r
257 =2D-- a/emacs/notmuch-lib.el\r
258 +++ b/emacs/notmuch-lib.el\r
259 @@ -120,6 +120,15 @@ within the current window."\r
260        (or (memq prop buffer-invisibility-spec)\r
261           (assq prop buffer-invisibility-spec)))))\r
262 =20\r
263 +(defun notmuch-remove-if-not (predicate list)\r
264 +  "Return a copy of LIST with all items not satisfying PREDICATE removed."\r
265 +  (let (out)\r
266 +    (while list\r
267 +      (when (funcall predicate (car list))\r
268 +        (push (car list) out))\r
269 +      (setq list (cdr list)))\r
270 +    (nreverse out)))\r
271 +\r
272  ; This lets us avoid compiling these replacement functions when emacs\r
273  ; is sufficiently new enough to supply them alone. We do the macro\r
274  ; treatment rather than just wrapping our defun calls in a when form\r
275 =2D-=20\r
276 1.7.5.1\r
277 \r
278 \r
279 --=-=-=--\r
280 \r
281 --==-=-=\r
282 Content-Type: application/pgp-signature\r
283 \r
284 -----BEGIN PGP SIGNATURE-----\r
285 Version: GnuPG v1.4.11 (GNU/Linux)\r
286 \r
287 iQIcBAEBAgAGBQJN3XLyAAoJEIaTAtce+Z+JuE8QAJIOS5MBTRTHflriNhnPDR6b\r
288 n1nZZicPM0dzraf0O8Su2IA7R79ZLEiPD+poqCWJ3Kddf78lQjcwDoU2tTXVBSO0\r
289 BRWZAPjkIx7QcDeF+mr6R2rsqBgyn4JQQ6/8QgO6V4mWGOCNo1VZMjjQE0QXj3jA\r
290 p9rh7A22r+FlDtF/EXHPaA4+kaiwvnaHhOS1CGstDZxZ1J4BoYC7kvMUzk+51GLa\r
291 gbBQehazp06SDgAScSa647oXhXw6sjyUu5OGWyswaO+wuTq/fwAkyOP59xlfJpef\r
292 BZyWzG6HT1mT4NZn2V1bZUVixwg5A+xPRK0F/fzyk6e4nV4E3YyjUtimcpjm2yLh\r
293 S/KdT2VRcK+OnvOmiSni+LRE8LAmTaCVA6MJYW/R88fQTELXBF5nU8zx22QYyPES\r
294 EDFKaNCm77Um+LlkQ33P8UI8dS5JKQRgCiZ4IBuNhitmpKxhLo0e4GXow2J/QYyY\r
295 1nggnlpxN6TFzIIbELyg6dfjunQ75EUE+X53Vaz+5kzsZP2kg5wHkbMwnqatYtLq\r
296 zbEalh7oYd4AlWN4Wl42/oPvYjHvcTDC8hpHpysz/uYFpk/cW9+XCzpkVTg2T0h/\r
297 7MWcoNY9YqTWU5r62d9HKaX8Ikr0aeyA89lA2s7xMyCAAu0kz5u1FA5QdnOHre2B\r
298 pxvway8DVIOyGdZF4hHh\r
299 =Dvo2\r
300 -----END PGP SIGNATURE-----\r
301 --==-=-=--\r