Re: [PATCH 0/4] Allow specifying alternate names for addresses in other_email
[notmuch-archives.git] / ed / 80b55c96ed8d48aab3981d94576d583cce45df
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 85BF2431FD0\r
6         for <notmuch@notmuchmail.org>; Fri,  3 Jun 2011 06:46:15 -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 CwmAzRG32lU4 for <notmuch@notmuchmail.org>;\r
17         Fri,  3 Jun 2011 06:46:13 -0700 (PDT)\r
18 Received: from mail-bw0-f53.google.com (mail-bw0-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 B5589431FB6\r
22         for <notmuch@notmuchmail.org>; Fri,  3 Jun 2011 06:46:12 -0700 (PDT)\r
23 Received: by bwg12 with SMTP id 12so1942134bwg.26\r
24         for <notmuch@notmuchmail.org>; Fri, 03 Jun 2011 06:46:10 -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:subject:in-reply-to:references\r
28         :user-agent:date:message-id:mime-version:content-type;\r
29         bh=elyFdZpGSBSVGe7reUktidxptd8bCxKl3qqvwnNP4B8=;\r
30         b=jCqL+DPVyQiwFZoKQXUtqWVqbCF6Adjke6ZVfhrRu/nmd8owdpObZcBhVk6tJP0vNk\r
31         TgH9kw32yyF3jSr9Rrguk+dUEmdzFWkad1NJZK/3G9SN3UJx3uIl5Lmvweq46qWblApF\r
32         CcLio2M3LtswB06uqrii4aIKNXYqWFCpJ+5mU=\r
33 DomainKey-Signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma;\r
34         h=from:to:subject:in-reply-to:references:user-agent:date:message-id\r
35         :mime-version:content-type;\r
36         b=cWmKOdEKu3frw16c+B84VqK7sM4amJU1MTmIk3Sx+528Y1wpksmOR6fQA4pcFMJDkc\r
37         SvOJpIvf+IPv9+mxrCrjiEcp6L/WudloRHe+/WEg1/Car14jFQFFurMFNBRLaRxXe8W4\r
38         S7NmuAsqHZKzzvtUoN40JDXQZRCqXvw3JmKTE=\r
39 Received: by 10.204.71.193 with SMTP id i1mr2002573bkj.102.1307108770782;\r
40         Fri, 03 Jun 2011 06:46:10 -0700 (PDT)\r
41 Received: from localhost (dslb-088-069-146-026.pools.arcor-ip.net\r
42         [88.69.146.26])\r
43         by mx.google.com with ESMTPS id k16sm1283227bks.13.2011.06.03.06.46.06\r
44         (version=TLSv1/SSLv3 cipher=OTHER);\r
45         Fri, 03 Jun 2011 06:46:08 -0700 (PDT)\r
46 From: Daniel Schoepe <daniel.schoepe@googlemail.com>\r
47 To: notmuch@notmuchmail.org\r
48 Subject: Re: [PATCH] emacs: User-defined sections in notmuch-hello\r
49 In-Reply-To: <874o4g563y.fsf@gilead.invalid>\r
50 References: <874o4g563y.fsf@gilead.invalid>\r
51 User-Agent: Notmuch/0.5-172-g3faaff1 (http://notmuchmail.org) Emacs/23.3.1\r
52         (x86_64-pc-linux-gnu)\r
53 Date: Fri, 03 Jun 2011 15:46:00 +0200\r
54 Message-ID: <87tyc7hvtz.fsf@gilead.invalid>\r
55 MIME-Version: 1.0\r
56 Content-Type: multipart/signed; boundary="==-=-=";\r
57         micalg=pgp-sha1; protocol="application/pgp-signature"\r
58 X-BeenThere: notmuch@notmuchmail.org\r
59 X-Mailman-Version: 2.1.13\r
60 Precedence: list\r
61 List-Id: "Use and development of the notmuch mail system."\r
62         <notmuch.notmuchmail.org>\r
63 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
64         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
65 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
66 List-Post: <mailto:notmuch@notmuchmail.org>\r
67 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
68 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
69         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
70 X-List-Received-Date: Fri, 03 Jun 2011 13:46:15 -0000\r
71 \r
72 --==-=-=\r
73 Content-Type: multipart/mixed; boundary="=-=-="\r
74 \r
75 --=-=-=\r
76 Content-Type: text/plain\r
77 \r
78 On Fri, 27 May 2011 20:52:01 +0200, Daniel Schoepe <daniel.schoepe@googlemail.com> wrote:\r
79 > I'll also work on some tests for this functionality, (if no one\r
80 > has big, structural complaints about the code).\r
81 \r
82 I rebased my patch against the current master and wrote some tests.\r
83 \r
84 \r
85 --=-=-=\r
86 Content-Type: text/x-diff\r
87 Content-Disposition: inline;\r
88  filename=0001-emacs-User-defined-sections-in-notmuch-hello.patch\r
89 Content-Transfer-Encoding: quoted-printable\r
90 \r
91 From=2042b87fca9b8b2ca5ba6748185dac4e945d7c594b Mon Sep 17 00:00:00 2001\r
92 From: Daniel Schoepe <daniel.schoepe@googlemail.com>\r
93 Date: Thu, 26 May 2011 23:03:22 +0200\r
94 Subject: [PATCH 1/2] emacs: User-defined sections in notmuch-hello\r
95 \r
96 This patch allows the user to define various sections that will\r
97 be displayed in notmuch-hello. I tried to keep the section\r
98 description flexible, so it allows different queries for the\r
99 tag buttons and the counts next to them, as well as hiding items\r
100 with zero results.\r
101 \r
102 The sections are (hopefully) fully editable using customize.\r
103 \r
104 I have not yet rewritten the saved-searches portion using this\r
105 mechanism, to avoid breaking the configurations of many users.\r
106 =2D--\r
107  emacs/notmuch-hello.el                             |  333 ++++++++++++++++=\r
108 ----\r
109  emacs/notmuch-lib.el                               |   22 +-\r
110  test/emacs.expected-output/notmuch-hello           |    2 +-\r
111  .../notmuch-hello-no-saved-searches                |    2 +-\r
112  .../emacs.expected-output/notmuch-hello-with-empty |    2 +-\r
113  5 files changed, 282 insertions(+), 79 deletions(-)\r
114 \r
115 diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el\r
116 index 916cda1..f014357 100644\r
117 =2D-- a/emacs/notmuch-hello.el\r
118 +++ b/emacs/notmuch-hello.el\r
119 @@ -55,24 +55,115 @@\r
120    :type 'boolean\r
121    :group 'notmuch)\r
122 =20\r
123 =2D(defcustom notmuch-hello-tag-list-make-query nil\r
124 =2D  "Function or string to generate queries for the all tags list.\r
125 =2D\r
126 =2DThis variable controls which query results are shown for each tag\r
127 =2Din the \"all tags\" list. If nil, it will use all messages with\r
128 =2Dthat tag. If this is set to a string, it is used as a filter for\r
129 =2Dmessages having that tag (equivalent to \"tag:TAG and (THIS-VARIABLE)\").\r
130 =2DFinally this can be a function that will be called for each tag and\r
131 =2Dshould return a filter for that tag, or nil to hide the tag."\r
132 =2D  :type '(choice (const :tag "All messages" nil)\r
133 =2D              (const :tag "Unread messages" "tag:unread")\r
134 =2D              (const :tag "Custom filter" string)\r
135 =2D              (const :tag "Custom filter function" function))\r
136 =2D  :group 'notmuch)\r
137 =2D\r
138 =2D(defcustom notmuch-hello-hide-tags nil\r
139 =2D  "List of tags to be hidden in the \"all tags\"-section."\r
140 =2D  :type '(repeat string)\r
141 +(defvar notmuch-hello-section-all-tags\r
142 +  (list :title "All tags:"\r
143 +       :type 'eachtag)\r
144 +  "Default section definition for the \"all tags\" section.")\r
145 +\r
146 +(defvar notmuch-hello-section-unread-tags\r
147 +  (list :title "All tags, unread only:"\r
148 +       :type 'eachtag\r
149 +       :make-query "tag:unread")\r
150 +  "Show and count only unread messages for each tag.")\r
151 +\r
152 +(defvar notmuch-hello-hidden-sections nil\r
153 +  "Sections that are hidden in notmuch-hello")\r
154 +\r
155 +(defvar notmuch-hello-first-run t\r
156 +  "Internal variable for hiding sections with :hidden-on-startup")\r
157 +\r
158 +(define-widget 'notmuch-section-query-type 'lazy\r
159 +  "Customize-type for query items"\r
160 +  :tag "Query item"\r
161 +  :type '(list (string :tag "Search title")\r
162 +              (string :tag "Query to use")\r
163 +              (choice :tag "Query for message count"\r
164 +                      (const :tag "Use previous query" nil)\r
165 +                      (string :tag "Different query"))))\r
166 +\r
167 +(define-widget 'notmuch-section-make-query-type 'lazy\r
168 +  "Customize-type for query functions"\r
169 +  :tag "Query function"\r
170 +  :type '(choice (const :tag "All messages with tag" nil)\r
171 +                (const :tag "Only unread messages" "tag:unread")\r
172 +                (string :tag "Custom filter string")\r
173 +                (function :tag "Custom filter function")))\r
174 +\r
175 +(define-widget 'notmuch-section-type 'lazy\r
176 +  "Customize-type for sections"\r
177 +  :tag "Custom section"\r
178 +  :type\r
179 +  '(plist :options (((const :tag "Title for this section" :title)\r
180 +                    string)\r
181 +                   ((const :tag "Type of this section" :type)\r
182 +                    (choice (const :tag "One item for each tag"\r
183 +                                   eachtag)\r
184 +                            (const :tag "Custom list of searches"\r
185 +                                   query-list)))\r
186 +                   ((const :tag "Function to generate a query, ignored if custom list"\r
187 +                           :make-query)\r
188 +                    notmuch-section-make-query)\r
189 +                   ((const :tag "Function to generate counts, ignored if custom list"\r
190 +                           :make-count)\r
191 +                    notmuch-section-make-query)\r
192 +                   ((const :tag "Function to create titles for tag entries, ignored if =\r
193 custom list"\r
194 +                           :make-title)\r
195 +                    (choice (const :tag "The tag itself" nil)\r
196 +                            (function :tag "Custom function")))\r
197 +                   ((const :tag "List of tags to hide, ignored if custom list"\r
198 +                           :hide-tags)\r
199 +                    (repeat (string :tag "tag")))\r
200 +                   ((const :tag "Search queries, only used if custom list"\r
201 +                           :items)\r
202 +                    (repeat notmuch-section-query))\r
203 +                   ((const :tag "Hide if there are no results" :hide-empty)\r
204 +                    boolean)\r
205 +                   ((const :tag "Where should this be positioned" :position)\r
206 +                    (choice (const :tag "Before the search input" before)\r
207 +                            (const :tag "After the search input" after))))))\r
208 +\r
209 +(defcustom notmuch-hello-sections (list notmuch-hello-section-all-tags)\r
210 +  "Sections to be displayed in notmuch-hello.\r
211 +\r
212 +This variable does not include the saved-searches section, which\r
213 +is handled separately.\r
214 +This variable should be a list of plists with the following\r
215 +possible properties:\r
216 +\r
217 +:title - The title of the section\r
218 +:type - Can be 'eachtag or 'query-list, If 'eachtag, generate one\r
219 +        item for each tag, otherwise use a fixed set of items.\r
220 +The following options are only used when type is 'eachtag:\r
221 +:make-query - This can be a query string that is used as a filter for all\r
222 +              messages that contain this tag. This can also be a function\r
223 +              that is given is tag and should return a filter query. If\r
224 +              it returns nil, the tag will be hidden. If nil, all\r
225 +              messages having the tag will be used.\r
226 +:make-count - Query used to generate message counts next to the labels,\r
227 +              same type as :make-query. If this is nil, the same query as\r
228 +              above will be used.\r
229 +:make-title - Function to generate an alternative title for each tag item.\r
230 +              Can be nil.\r
231 +:hide-tags - List of tags that will be hidden.\r
232 +\r
233 +If :type is 'query-list, the following entry must be set:\r
234 +:items - List of cons-cells of a title and a query for that item,\r
235 +         and/or of lists of the form (TITLE QUERY COUNT), where COUNT is\r
236 +         used to generate the message count instead of QUERY. (To make\r
237 +         the customize-interface nicer, COUNT is also allowed to be nil).\r
238 +\r
239 +The following properties are valid for both :type's:\r
240 +:hide-empty - If non-nil, hide items that have no matching messages\r
241 +:position - If 'before, it will be displayed before the search input form,=\r
242  otherwise\r
243 +            after the recent searches.\r
244 +:hidden-on-startup - If non-nil, this section will be hidden when notmuch-=\r
245 hello\r
246 +                     is first run."\r
247 +  :type `(repeat\r
248 +         (choice (const :tag "Show all messages for each tag"\r
249 +                        ,notmuch-hello-section-all-tags)\r
250 +                 (const :tag "Only unread messages for each tag"\r
251 +                        ,notmuch-hello-section-unread-tags)\r
252 +                 notmuch-section-type))\r
253    :group 'notmuch)\r
254 =20\r
255  (defface notmuch-hello-logo-background\r
256 @@ -238,12 +329,32 @@ should be. Returns a cons cell `(tags-per-line width)=\r
257 '."\r
258                                    (* tags-per-line (+ 9 1))))\r
259                            tags-per-line))))\r
260 =20\r
261 =2D(defun notmuch-hello-insert-tags (tag-alist widest target)\r
262 +(defun notmuch-hello-get-count-query (query-item)\r
263 +  (if (consp (cdr query-item))\r
264 +      (or (third query-item) (second query-item))\r
265 +    (cdr query-item)))\r
266 +\r
267 +(defun notmuch-hello-insert-tags (tag-alist widest target &optional show-e=\r
268 mpty)\r
269    (let* ((tags-and-width (notmuch-hello-tags-per-line widest))\r
270          (tags-per-line (car tags-and-width))\r
271 +        (count-alist\r
272 +         (mapcar\r
273 +          (lambda (tag-entry)\r
274 +            (cons (car tag-entry)\r
275 +                  (string-to-number (notmuch-saved-search-count\r
276 +                                     (notmuch-hello-get-count-query tag-entry)))))\r
277 +          tag-alist))\r
278 +        (tag-alist-filtered\r
279 +         (if show-empty\r
280 +             tag-alist\r
281 +           (notmuch-remove-if-not\r
282 +            (lambda (tag-entry)\r
283 +              ;; filter out entries that have 0 results\r
284 +              (and (not (eq 0 (cdr (assoc (car tag-entry) count-alist)))) tag-en=\r
285 try))\r
286 +            tag-alist)))\r
287          (widest (cdr tags-and-width))\r
288          (count 0)\r
289 =2D      (reordered-list (notmuch-hello-reflect tag-alist tags-per-line))\r
290 +        (reordered-list (notmuch-hello-reflect tag-alist-filtered tags-per-line))\r
291          ;; Hack the display of the buttons used.\r
292          (widget-push-button-prefix "")\r
293          (widget-push-button-suffix "")\r
294 @@ -254,11 +365,14 @@ should be. Returns a cons cell `(tags-per-line width)=\r
295 '."\r
296             ;; (not elem) indicates an empty slot in the matrix.\r
297             (when elem\r
298               (let* ((name (car elem))\r
299 =2D                  (query (cdr elem))\r
300 +                    (query (if (consp (cdr elem))\r
301 +                               (second elem)\r
302 +                             (cdr elem)))\r
303 +                    (count-query (notmuch-hello-get-count-query elem))\r
304                      (formatted-name (format "%s " name)))\r
305                 (widget-insert (format "%8s "\r
306                                        (notmuch-hello-nice-number\r
307 =2D                                     (string-to-number (notmuch-saved-search-count query)))))\r
308 +                                       (cdr (assoc name count-alist)))))\r
309                 (if (string=3D formatted-name target)\r
310                     (setq found-target-pos (point-marker)))\r
311                 (widget-create 'push-button\r
312 @@ -338,24 +452,94 @@ Complete list of currently available key bindings:\r
313   ;;(setq buffer-read-only t)\r
314  )\r
315 =20\r
316 =2D(defun notmuch-hello-generate-tag-alist ()\r
317 =2D  "Return an alist from tags to queries to display in the all-tags secti=\r
318 on."\r
319 =2D  (notmuch-remove-if-not\r
320 =2D   #'cdr\r
321 =2D   (mapcar (lambda (tag)\r
322 =2D          (cons tag\r
323 =2D                (cond\r
324 =2D                 ((functionp notmuch-hello-tag-list-make-query)\r
325 =2D                  (concat "tag:" tag " and ("\r
326 =2D                          (funcall notmuch-hello-tag-list-make-query tag) ")"))\r
327 =2D                 ((stringp notmuch-hello-tag-list-make-query)\r
328 =2D                  (concat "tag:" tag " and ("\r
329 =2D                          notmuch-hello-tag-list-make-query ")"))\r
330 =2D                 (t (concat "tag:" tag)))))\r
331 =2D        (notmuch-remove-if-not\r
332 =2D         (lambda (tag)\r
333 =2D           (not (member tag notmuch-hello-hide-tags)))\r
334 =2D         (process-lines notmuch-command "search-tags")))))\r
335 +(defun notmuch-hello-section-tag-to-title (section tag)\r
336 +  (let ((make-title (plist-get section :make-title)))\r
337 +    (if make-title\r
338 +       (funcall make-title tag)\r
339 +      tag)))\r
340 +\r
341 +(defun notmuch-hello-section-get-widest (section)\r
342 +  "Return widest title string in SECTION."\r
343 +  (if (member (plist-get section :title) notmuch-hello-hidden-sections)\r
344 +      0\r
345 +    (case (plist-get section :type)\r
346 +      ('eachtag (apply #'max\r
347 +                      (mapcar (lambda (tag)\r
348 +                                (length (notmuch-hello-section-tag-to-title section tag)))\r
349 +                              (notmuch-all-tags))))\r
350 +      ('query-list (apply #'max\r
351 +                         (mapcar (lambda (entry) (length (first entry)))\r
352 +                                 (plist-get section :items))))\r
353 +      (t (message (concat "Unknown section type: "=20\r
354 +                         (prin1-to-string (plist-get section :type))))))))\r
355 +=20=20\r
356 +(defun notmuch-hello-generate-tag-alist (section)\r
357 +  "Generate an alist of tags as expected by notmuch-insert-tags for SECTIO=\r
358 N.\r
359 +\r
360 +This function handles the special case that section is of type 'eachtag"\r
361 +  (let ((make-tag (lambda (make-entry tag)\r
362 +                   (cond\r
363 +                    ((functionp make-entry)\r
364 +                     (let ((query (funcall make-entry tag)))\r
365 +                       (and query\r
366 +                          (concat "tag:" tag " and (" query ")"))))\r
367 +                    ((stringp make-entry)\r
368 +                     (concat "tag:" tag " and (" make-entry ")"))\r
369 +                    (t (concat "tag:" tag))))))\r
370 +    ;; remove tags for which make-query returned nil\r
371 +    (delq nil\r
372 +         (mapcar (lambda (tag)\r
373 +                   (let ((title\r
374 +                          (notmuch-hello-section-tag-to-title section tag))\r
375 +                         (query (funcall make-tag\r
376 +                                         (plist-get section :make-query) tag))\r
377 +                         (count (plist-get section :make-count)))\r
378 +                     (and query\r
379 +                        (if count\r
380 +                            (list title query (funcall make-tag count tag))\r
381 +                          (cons title query)))))\r
382 +                 ;; remove tags from :hide-tags\r
383 +                 (notmuch-remove-if-not\r
384 +                  (lambda (tag)\r
385 +                    (not (member tag (plist-get section :hide-tags))))\r
386 +                  (notmuch-all-tags))))))\r
387 +\r
388 +(defun notmuch-hello-section-to-alist (section)\r
389 +  "Generate an alist of tags as expected by notmuch-insert-tags for SECTIO=\r
390 N."\r
391 +  (case (plist-get section :type)\r
392 +    ('eachtag (notmuch-hello-generate-tag-alist section))\r
393 +    ('query-list (plist-get section :items))\r
394 +    (t (message (concat "Unknown section type: "\r
395 +                       (prin1-to-string (plist-get section :type)))))))\r
396 +=09=20=20=20=20=20=20\r
397 +\r
398 +(defun notmuch-hello-insert-section (section widest target)\r
399 +"Insert all UI elements for SECTION in the current buffer."\r
400 +  (let* ((tags-alist (notmuch-hello-section-to-alist section))\r
401 +        (title (plist-get section :title))\r
402 +        (hidden (member title notmuch-hello-hidden-sections))\r
403 +        (hide-empty (plist-get section :hide-empty))\r
404 +        target-pos)\r
405 +    (widget-insert (concat "\n" title " "))\r
406 +    (when hidden\r
407 +      (widget-create 'push-button\r
408 +                    :notify `(lambda (widget &rest ignore)\r
409 +                               (setq notmuch-hello-hidden-sections\r
410 +                                     (delq ,title notmuch-hello-hidden-sections))\r
411 +                               (notmuch-hello-update))\r
412 +                    "show"))\r
413 +    (when (not hidden)\r
414 +      (widget-create 'push-button\r
415 +                    :notify `(lambda (widget &rest ignore)\r
416 +                               (add-to-list 'notmuch-hello-hidden-sections ,title)\r
417 +                               (notmuch-hello-update))\r
418 +                    "hide")\r
419 +      (widget-insert "\n\n")\r
420 +      (let ((start (point)))\r
421 +       (setq target-pos (notmuch-hello-insert-tags tags-alist widest target\r
422 +                                                   (not hide-empty)))\r
423 +       (indent-rigidly start (point) notmuch-hello-indent))\r
424 +      target-pos)))\r
425 =20\r
426  ;;;###autoload\r
427  (defun notmuch-hello (&optional no-display)\r
428 @@ -426,7 +610,30 @@ Complete list of currently available key bindings:\r
429        (widget-insert " messages.\n"))\r
430 =20\r
431      (let ((found-target-pos nil)\r
432 =2D       (final-target-pos nil))\r
433 +         (final-target-pos nil)\r
434 +         (upper-sections (notmuch-remove-if-not\r
435 +                          (lambda (section) (eq (plist-get section :position)\r
436 +                                           'before))\r
437 +                          notmuch-hello-sections))\r
438 +         (lower-sections (notmuch-remove-if-not\r
439 +                          (lambda (section) (not (eq (plist-get section :position)\r
440 +                                              'before)))\r
441 +                          notmuch-hello-sections)))\r
442 +\r
443 +      ;; handle sections that should be hidden initially\r
444 +      (when notmuch-hello-first-run\r
445 +       (mapc (lambda (section)\r
446 +               (if (plist-get section :hidden-on-startup)\r
447 +                   (add-to-list 'notmuch-hello-hidden-sections\r
448 +                                (plist-get section :title))))\r
449 +             notmuch-hello-sections)\r
450 +       ;; special case for notmuch-show-all-tags-list\r
451 +       (when (and (not notmuch-show-all-tags-list)\r
452 +                (member notmuch-hello-section-all-tags notmuch-hello-sections))\r
453 +         (add-to-list 'notmuch-hello-hidden-sections\r
454 +                      (plist-get notmuch-hello-section-all-tags :title)))\r
455 +       (setq notmuch-hello-first-run nil))\r
456 +\r
457        (let* ((saved-alist\r
458               ;; Filter out empty saved seaches if required.\r
459               (if notmuch-show-empty-saved-searches\r
460 @@ -435,9 +642,9 @@ Complete list of currently available key bindings:\r
461                       if (> (string-to-number (notmuch-saved-search-count (cdr elem))) 0)\r
462                       collect elem)))\r
463              (saved-widest (notmuch-hello-longest-label saved-alist))\r
464 =2D          (alltags-alist (if notmuch-show-all-tags-list (notmuch-hello-gener=\r
465 ate-tag-alist)))\r
466 =2D          (alltags-widest (notmuch-hello-longest-label alltags-alist))\r
467 =2D          (widest (max saved-widest alltags-widest)))\r
468 +            (sections-widest (apply #'max 0 (mapcar #'notmuch-hello-section-get-=\r
469 widest\r
470 +                                                    notmuch-hello-sections)))\r
471 +            (widest (max saved-widest sections-widest)))\r
472 =20\r
473         (when saved-alist\r
474           (widget-insert "\nSaved searches: ")\r
475 @@ -448,11 +655,19 @@ Complete list of currently available key bindings:\r
476           (widget-insert "\n\n")\r
477           (setq final-target-pos (point-marker))\r
478           (let ((start (point)))\r
479 =2D         (setq found-target-pos (notmuch-hello-insert-tags saved-alist wides=\r
480 t target))\r
481 +           (setq found-target-pos (notmuch-hello-insert-tags saved-alist widest =\r
482 target\r
483 +                                                             notmuch-show-empty-saved-searches))\r
484             (if found-target-pos\r
485                 (setq final-target-pos found-target-pos))\r
486             (indent-rigidly start (point) notmuch-hello-indent)))\r
487 =20\r
488 +       (mapc (lambda (section)\r
489 +               (setq found-target-pos\r
490 +                     (notmuch-hello-insert-section section widest target))\r
491 +               (unless final-target-pos\r
492 +                   (setq final-target-pos found-target-pos)))\r
493 +             upper-sections)\r
494 +\r
495         (widget-insert "\nSearch: ")\r
496         (setq notmuch-hello-search-bar-marker (point-marker))\r
497         (widget-create 'editable-field\r
498 @@ -507,28 +722,12 @@ Complete list of currently available key bindings:\r
499                   notmuch-hello-recent-searches)\r
500             (indent-rigidly start (point) notmuch-hello-indent)))\r
501 =20\r
502 =2D     (when alltags-alist\r
503 =2D       (widget-insert "\nAll tags: ")\r
504 =2D       (widget-create 'push-button\r
505 =2D                      :notify (lambda (widget &rest ignore)\r
506 =2D                                (setq notmuch-show-all-tags-list nil)\r
507 =2D                                (notmuch-hello-update))\r
508 =2D                      "hide")\r
509 =2D       (widget-insert "\n\n")\r
510 =2D       (let ((start (point)))\r
511 =2D         (setq found-target-pos (notmuch-hello-insert-tags alltags-alist wid=\r
512 est target))\r
513 =2D         (if (not final-target-pos)\r
514 =2D             (setq final-target-pos found-target-pos))\r
515 =2D         (indent-rigidly start (point) notmuch-hello-indent)))\r
516 =2D\r
517 =2D     (widget-insert "\n")\r
518 =2D\r
519 =2D     (if (not notmuch-show-all-tags-list)\r
520 =2D         (widget-create 'push-button\r
521 =2D                        :notify (lambda (widget &rest ignore)\r
522 =2D                                  (setq notmuch-show-all-tags-list t)\r
523 =2D                                  (notmuch-hello-update))\r
524 =2D                        "Show all tags")))\r
525 +       (mapc (lambda (section)\r
526 +               (setq found-target-pos\r
527 +                     (notmuch-hello-insert-section section widest target))\r
528 +               (unless final-target-pos\r
529 +                   (setq final-target-pos found-target-pos)))\r
530 +             lower-sections))\r
531 =20\r
532        (let ((start (point)))\r
533         (widget-insert "\n\n")\r
534 diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el\r
535 index a21dc14..bc46334 100644\r
536 =2D-- a/emacs/notmuch-lib.el\r
537 +++ b/emacs/notmuch-lib.el\r
538 @@ -103,6 +103,19 @@ the user hasn't set this variable with the old or new =\r
539 value."\r
540    (kill-new text)\r
541    (message "Stashed: %s" text))\r
542 =20\r
543 +(defun notmuch-all-tags ()\r
544 +  "Return a list of all tags in the database"\r
545 +  (process-lines "notmuch" "search-tags"))\r
546 +\r
547 +(defun notmuch-remove-if-not (predicate list)\r
548 +  "Return a copy of LIST with all items not satisfying PREDICATE removed."\r
549 +  (let (out)\r
550 +    (while list\r
551 +      (when (funcall predicate (car list))\r
552 +        (push (car list) out))\r
553 +      (setq list (cdr list)))\r
554 +    (nreverse out)))\r
555 +\r
556  ;;\r
557 =20\r
558  ;; XXX: This should be a generic function in emacs somewhere, not\r
559 @@ -120,15 +133,6 @@ within the current window."\r
560        (or (memq prop buffer-invisibility-spec)\r
561           (assq prop buffer-invisibility-spec)))))\r
562 =20\r
563 =2D(defun notmuch-remove-if-not (predicate list)\r
564 =2D  "Return a copy of LIST with all items not satisfying PREDICATE removed=\r
565 ."\r
566 =2D  (let (out)\r
567 =2D    (while list\r
568 =2D      (when (funcall predicate (car list))\r
569 =2D        (push (car list) out))\r
570 =2D      (setq list (cdr list)))\r
571 =2D    (nreverse out)))\r
572 =2D\r
573  ; This lets us avoid compiling these replacement functions when emacs\r
574  ; is sufficiently new enough to supply them alone. We do the macro\r
575  ; treatment rather than just wrapping our defun calls in a when form\r
576 diff --git a/test/emacs.expected-output/notmuch-hello b/test/emacs.expected=\r
577 -output/notmuch-hello\r
578 index 64b7e42..f98f132 100644\r
579 =2D-- a/test/emacs.expected-output/notmuch-hello\r
580 +++ b/test/emacs.expected-output/notmuch-hello\r
581 @@ -6,7 +6,7 @@ Saved searches: [edit]\r
582 =20\r
583  Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
584 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
585 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
586 =20\r
587 =2D[Show all tags]\r
588 +All tags: [show]\r
589 =20\r
590          Type a search query and hit RET to view matching threads.\r
591                 Edit saved searches with the `edit' button.\r
592 diff --git a/test/emacs.expected-output/notmuch-hello-no-saved-searches b/t=\r
593 est/emacs.expected-output/notmuch-hello-no-saved-searches\r
594 index 7f8206a..46172ee 100644\r
595 =2D-- a/test/emacs.expected-output/notmuch-hello-no-saved-searches\r
596 +++ b/test/emacs.expected-output/notmuch-hello-no-saved-searches\r
597 @@ -2,7 +2,7 @@\r
598 =20\r
599  Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
600 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
601 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
602 =20\r
603 =2D[Show all tags]\r
604 +All tags: [show]\r
605 =20\r
606          Type a search query and hit RET to view matching threads.\r
607                 Edit saved searches with the `edit' button.\r
608 diff --git a/test/emacs.expected-output/notmuch-hello-with-empty b/test/ema=\r
609 cs.expected-output/notmuch-hello-with-empty\r
610 index a9ed630..eb563cc 100644\r
611 =2D-- a/test/emacs.expected-output/notmuch-hello-with-empty\r
612 +++ b/test/emacs.expected-output/notmuch-hello-with-empty\r
613 @@ -6,7 +6,7 @@ Saved searches: [edit]\r
614 =20\r
615  Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
616 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
617 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
618 =20\r
619 =2D[Show all tags]\r
620 +All tags: [show]\r
621 =20\r
622          Type a search query and hit RET to view matching threads.\r
623                 Edit saved searches with the `edit' button.\r
624 =2D-=20\r
625 1.7.5.3\r
626 \r
627 \r
628 --=-=-=\r
629 Content-Type: text/x-diff\r
630 Content-Disposition: inline;\r
631  filename=0002-emacs-A-few-tests-for-user-defined-sections.patch\r
632 Content-Transfer-Encoding: quoted-printable\r
633 \r
634 From=205a401e74359eafa9e6fc83c19051402270cb3662 Mon Sep 17 00:00:00 2001\r
635 From: Daniel Schoepe <daniel.schoepe@googlemail.com>\r
636 Date: Fri, 3 Jun 2011 15:42:35 +0200\r
637 Subject: [PATCH 2/2] emacs: A few tests for user-defined sections\r
638 \r
639 =2D--\r
640  test/emacs                                         |   29 ++++++++++++++++=\r
641 ++++\r
642  .../notmuch-hello-new-section                      |   17 +++++++++++\r
643  .../notmuch-hello-section-before                   |   18 ++++++++++++\r
644  .../notmuch-hello-section-counts                   |   18 ++++++++++++\r
645  .../notmuch-hello-section-hidden-tag               |   17 +++++++++++\r
646  .../notmuch-hello-section-with-empty               |   17 +++++++++++\r
647  6 files changed, 116 insertions(+), 0 deletions(-)\r
648  create mode 100644 test/emacs.expected-output/notmuch-hello-new-section\r
649  create mode 100644 test/emacs.expected-output/notmuch-hello-section-before\r
650  create mode 100644 test/emacs.expected-output/notmuch-hello-section-counts\r
651  create mode 100644 test/emacs.expected-output/notmuch-hello-section-hidden=\r
652 -tag\r
653  create mode 100644 test/emacs.expected-output/notmuch-hello-section-with-e=\r
654 mpty\r
655 \r
656 diff --git a/test/emacs b/test/emacs\r
657 index 792492f..7fea4ea 100755\r
658 =2D-- a/test/emacs\r
659 +++ b/test/emacs\r
660 @@ -31,6 +31,35 @@ output=3D$(test_emacs '(notmuch-hello) (goto-char (point=\r
661 -min)) (re-search-forward\r
662  expected=3D$(cat $EXPECTED/notmuch-hello-view-inbox)\r
663  test_expect_equal "$output" "$expected"\r
664 =20\r
665 +test_begin_subtest "User defined section with inbox tag"\r
666 +output=3D$(test_emacs "(setq notmuch-hello-sections '((:title \"Test:\" :t=\r
667 ype query-list :items ((\"inbox\" . \"tag:inbox\"))))) (notmuch-hello) (pri=\r
668 nc (buffer-string))")\r
669 +expected=3D$(cat $EXPECTED/notmuch-hello-new-section)\r
670 +test_expect_equal "$output" "$expected"\r
671 +\r
672 +test_begin_subtest "User defined section with empty, hidden entry"\r
673 +output=3D$(test_emacs "(setq notmuch-hello-sections '((:title \"Test-with-=\r
674 empty:\" :type query-list :items\r
675 +             ((\"inbox\" . \"tag:inbox\") (\"doesnotexist\" . \"tag:doesno=\r
676 texist\"))\r
677 +             :hide-empty t)))\r
678 +             (notmuch-hello)\r
679 +             (princ (buffer-string))")\r
680 +expected=3D$(cat $EXPECTED/notmuch-hello-section-with-empty)\r
681 +test_expect_equal "$output" "$expected"\r
682 +\r
683 +test_begin_subtest "User defined section, unread tag filtered out"\r
684 +output=3D$(test_emacs "(setq notmuch-hello-sections '((:title \"Test-with-=\r
685 filtered:\" :type eachtag :hide-tags (\"unread\")))) (notmuch-hello) (princ=\r
686  (buffer-string))")\r
687 +expected=3D$(cat $EXPECTED/notmuch-hello-section-hidden-tag)\r
688 +test_expect_equal "$output" "$expected"\r
689 +\r
690 +test_begin_subtest "User defined section, different query for counts"\r
691 +output=3D$(test_emacs "(setq notmuch-hello-sections '((:title \"Test-with-=\r
692 counts:\" :type eachtag :make-count \"tag:signed\"))) (notmuch-hello) (prin=\r
693 c (buffer-string))")\r
694 +expected=3D$(cat $EXPECTED/notmuch-hello-section-counts)\r
695 +test_expect_equal "$output" "$expected"\r
696 +\r
697 +test_begin_subtest "User defined section, positioned before search input"\r
698 +output=3D$(test_emacs "(setq notmuch-hello-sections '((:title \"Test-befor=\r
699 e\" :type eachtag :position before))) (notmuch-hello) (princ (buffer-string=\r
700 ))")\r
701 +expected=3D$(cat $EXPECTED/notmuch-hello-section-before)\r
702 +test_expect_equal "$output" "$expected"\r
703 +\r
704  test_begin_subtest "Basic notmuch-show view in emacs"\r
705  maildir_storage_thread=3D$(notmuch search --output=3Dthreads id:2009111719=\r
706 0054.GU3165@dottiness.seas.harvard.edu)\r
707  output=3D$(test_emacs "(notmuch-show \"$maildir_storage_thread\") (princ (=\r
708 buffer-string))")\r
709 diff --git a/test/emacs.expected-output/notmuch-hello-new-section b/test/em=\r
710 acs.expected-output/notmuch-hello-new-section\r
711 new file mode 100644\r
712 index 0000000..23e0068\r
713 =2D-- /dev/null\r
714 +++ b/test/emacs.expected-output/notmuch-hello-new-section\r
715 @@ -0,0 +1,17 @@\r
716 +   Welcome to notmuch. You have 50 messages.\r
717 +\r
718 +Saved searches: [edit]\r
719 +\r
720 +         50 inbox           50 unread=20=20=20=20\r
721 +\r
722 +Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
723 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
724 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
725 +\r
726 +Test: [hide]\r
727 +\r
728 +         50 inbox=20=20=20=20=20\r
729 +\r
730 +\r
731 +        Type a search query and hit RET to view matching threads.\r
732 +               Edit saved searches with the `edit' button.\r
733 +  Hit RET or click on a saved search or tag name to view matching threads.\r
734 +    `=3D' refreshes this screen. `s' jumps to the search box. `q' to quit.\r
735 diff --git a/test/emacs.expected-output/notmuch-hello-section-before b/test=\r
736 /emacs.expected-output/notmuch-hello-section-before\r
737 new file mode 100644\r
738 index 0000000..a5781ce\r
739 =2D-- /dev/null\r
740 +++ b/test/emacs.expected-output/notmuch-hello-section-before\r
741 @@ -0,0 +1,18 @@\r
742 +   Welcome to notmuch. You have 50 messages.\r
743 +\r
744 +Saved searches: [edit]\r
745 +\r
746 +         50 inbox                 50 unread=20=20=20=20=20=20=20=20=20=20\r
747 +\r
748 +Test-before [hide]\r
749 +\r
750 +          4 attachment             7 signed=20=20=20=20=20=20=20=20=20=20\r
751 +         50 inbox                 50 unread=20=20=20=20=20=20=20=20=20=20\r
752 +\r
753 +Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
754 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
755 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
756 +\r
757 +\r
758 +        Type a search query and hit RET to view matching threads.\r
759 +               Edit saved searches with the `edit' button.\r
760 +  Hit RET or click on a saved search or tag name to view matching threads.\r
761 +    `=3D' refreshes this screen. `s' jumps to the search box. `q' to quit.\r
762 diff --git a/test/emacs.expected-output/notmuch-hello-section-counts b/test=\r
763 /emacs.expected-output/notmuch-hello-section-counts\r
764 new file mode 100644\r
765 index 0000000..c22d491\r
766 =2D-- /dev/null\r
767 +++ b/test/emacs.expected-output/notmuch-hello-section-counts\r
768 @@ -0,0 +1,18 @@\r
769 +   Welcome to notmuch. You have 50 messages.\r
770 +\r
771 +Saved searches: [edit]\r
772 +\r
773 +         50 inbox                 50 unread=20=20=20=20=20=20=20=20=20=20\r
774 +\r
775 +Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
776 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
777 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
778 +\r
779 +Test-with-counts: [hide]\r
780 +\r
781 +          2 attachment             7 signed=20=20=20=20=20=20=20=20=20=20\r
782 +          7 inbox                  7 unread=20=20=20=20=20=20=20=20=20=20\r
783 +\r
784 +\r
785 +        Type a search query and hit RET to view matching threads.\r
786 +               Edit saved searches with the `edit' button.\r
787 +  Hit RET or click on a saved search or tag name to view matching threads.\r
788 +    `=3D' refreshes this screen. `s' jumps to the search box. `q' to quit.\r
789 diff --git a/test/emacs.expected-output/notmuch-hello-section-hidden-tag b/=\r
790 test/emacs.expected-output/notmuch-hello-section-hidden-tag\r
791 new file mode 100644\r
792 index 0000000..d6d31b3\r
793 =2D-- /dev/null\r
794 +++ b/test/emacs.expected-output/notmuch-hello-section-hidden-tag\r
795 @@ -0,0 +1,17 @@\r
796 +   Welcome to notmuch. You have 50 messages.\r
797 +\r
798 +Saved searches: [edit]\r
799 +\r
800 +         50 inbox                 50 unread=20=20=20=20=20=20=20=20=20=20\r
801 +\r
802 +Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
803 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
804 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
805 +\r
806 +Test-with-filtered: [hide]\r
807 +\r
808 +          4 attachment            50 inbox                  7 signed=20=20=20=20=\r
809 =20=20=20=20=20=20\r
810 +\r
811 +\r
812 +        Type a search query and hit RET to view matching threads.\r
813 +               Edit saved searches with the `edit' button.\r
814 +  Hit RET or click on a saved search or tag name to view matching threads.\r
815 +    `=3D' refreshes this screen. `s' jumps to the search box. `q' to quit.\r
816 diff --git a/test/emacs.expected-output/notmuch-hello-section-with-empty b/=\r
817 test/emacs.expected-output/notmuch-hello-section-with-empty\r
818 new file mode 100644\r
819 index 0000000..7ab80f2\r
820 =2D-- /dev/null\r
821 +++ b/test/emacs.expected-output/notmuch-hello-section-with-empty\r
822 @@ -0,0 +1,17 @@\r
823 +   Welcome to notmuch. You have 50 messages.\r
824 +\r
825 +Saved searches: [edit]\r
826 +\r
827 +         50 inbox                 50 unread=20=20=20=20=20=20=20=20=20=20\r
828 +\r
829 +Search:=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
830 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=\r
831 =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20\r
832 +\r
833 +Test-with-empty: [hide]\r
834 +\r
835 +         50 inbox=20=20=20=20=20=20=20=20=20=20=20\r
836 +\r
837 +\r
838 +        Type a search query and hit RET to view matching threads.\r
839 +               Edit saved searches with the `edit' button.\r
840 +  Hit RET or click on a saved search or tag name to view matching threads.\r
841 +    `=3D' refreshes this screen. `s' jumps to the search box. `q' to quit.\r
842 =2D-=20\r
843 1.7.5.3\r
844 \r
845 \r
846 --=-=-=--\r
847 \r
848 --==-=-=\r
849 Content-Type: application/pgp-signature\r
850 \r
851 -----BEGIN PGP SIGNATURE-----\r
852 Version: GnuPG v1.4.11 (GNU/Linux)\r
853 \r
854 iQIcBAEBAgAGBQJN6OWYAAoJEIaTAtce+Z+JPCIP+wagZv/LafBC0u3qORTG1Gbp\r
855 kkjIMw1/DPdRDZs/MJuQQEWCPD2qgzJOW8XjPhgoHF3QLPwwcxn3YrcEfcWjkn2A\r
856 eADNzZjjKCqJ98yehQufeLyP5Er7v4uCeVAqEyJJSfJOU4ZbdjpwpP7xpYsxqRpV\r
857 EeGDKhwz64qJCuaXC0Wg037kT4sZzO4wdIbgjvCYeljJ8EEFd4brBVoVffTkFmij\r
858 nbRLgEI7Aq7pt5yzl0Qe8VKVPFQLrzzH1Yh6VLP9neW7hETJFpWuAaNxdqey4LcG\r
859 1kzkLv48NNE4NUMmed7AinUdwnU9bzOD0XC8bCBExUyX8yTPJatR3VnZjeZHSHVx\r
860 qoIbZhajJXPcOOk7ZGomy5CZqzCYcNuT/iHK16dzfmveIEt9a/7csUtX75yOwHI6\r
861 lvqPlSudAbTOF9sPtdxKPPc5cwlCi55lgV0qjlkuKVsqOZu0YqwbU+RWNGF7cvNr\r
862 p5F4gOWYP5PnYN/S1I5EL4Csm+hOau+qJqdpaDC3I/RmZfvX65WwH6SHSQW0En30\r
863 c42kX3i3wP7NVGWEoE6pBRqhTvLbFphLI77PqtL7/wF+eO4ic8adYJoKOlXu/i2I\r
864 IiZWrocGoc9s4LeynnsJsWTUf13sXJfgId4pegisb+hMPX3sPk83pMbXJeJ42Op/\r
865 MFshrDuucmIYVe7VCYTQ\r
866 =AFxu\r
867 -----END PGP SIGNATURE-----\r
868 --==-=-=--\r