1 Return-Path: <markwalters1009@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 CB7A1431FC2
\r
6 for <notmuch@notmuchmail.org>; Fri, 14 Feb 2014 01:15:34 -0800 (PST)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=0.201 tagged_above=-999 required=5
\r
12 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,
\r
13 FREEMAIL_ENVFROM_END_DIGIT=1, FREEMAIL_FROM=0.001,
\r
14 RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled
\r
15 Received: from olra.theworths.org ([127.0.0.1])
\r
16 by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)
\r
17 with ESMTP id eZH9G3yvFwvE for <notmuch@notmuchmail.org>;
\r
18 Fri, 14 Feb 2014 01:15:30 -0800 (PST)
\r
19 Received: from mail-wg0-f51.google.com (mail-wg0-f51.google.com
\r
20 [74.125.82.51]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (No client
\r
21 certificate requested) by olra.theworths.org (Postfix) with ESMTPS id
\r
22 1C6AF431FB6 for <notmuch@notmuchmail.org>; Fri, 14 Feb 2014 01:15:29 -0800
\r
24 Received: by mail-wg0-f51.google.com with SMTP id n12so183939wgh.18
\r
25 for <notmuch@notmuchmail.org>; Fri, 14 Feb 2014 01:15:27 -0800 (PST)
\r
26 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113;
\r
27 h=from:to:subject:date:message-id:in-reply-to:references;
\r
28 bh=BxZI08p31KmOxc70Ea/BcOAVyJOE+gK2pt1SuAImP6I=;
\r
29 b=0tnfCvr3WDn40CEvqz61rma0+bO5K4o2Nm0oidNOdpIY3h7+1jNa2EuFAt4VAHC2Dh
\r
30 tMkNaOQjrIZfdCN8CHlH914gs0Ucx2vmiK254JkmogUmLa0ueYI12f/MUjvmFOQINrTr
\r
31 I2SlMsCFQ2n/uYX5pEl/OtzDla1dO8RCouiP2xktsY97SSxBFBUfw794ulOEZUEWKXxn
\r
32 11SDGJtfPIGYL7oJst3c4niD0SXa015MHQcop/pPxL+0aUUxnD3BL6pNBD20tMEP4b6C
\r
33 rK0tzK+YqYwnpaWBfd4cmZPXAWDzc5Yfyj9CatLHnBe7Ew0PtWQRfGwxY9b5MGtEYvUC
\r
35 X-Received: by 10.194.2.70 with SMTP id 6mr4906069wjs.25.1392369327419;
\r
36 Fri, 14 Feb 2014 01:15:27 -0800 (PST)
\r
37 Received: from localhost (93-97-24-31.zone5.bethere.co.uk. [93.97.24.31])
\r
38 by mx.google.com with ESMTPSA id ev4sm2715601wib.1.2014.02.14.01.15.26
\r
39 for <multiple recipients>
\r
40 (version=TLSv1.2 cipher=RC4-SHA bits=128/128);
\r
41 Fri, 14 Feb 2014 01:15:26 -0800 (PST)
\r
42 From: Mark Walters <markwalters1009@gmail.com>
\r
43 To: notmuch@notmuchmail.org,
\r
44 Austin Clements <amdragon@MIT.EDU>
\r
45 Subject: [WIP Patch 1/7] Make keys of notmuch-tag-formats regexps and use
\r
47 Date: Fri, 14 Feb 2014 09:15:13 +0000
\r
48 Message-Id: <1392369319-24508-2-git-send-email-markwalters1009@gmail.com>
\r
49 X-Mailer: git-send-email 1.7.9.1
\r
50 In-Reply-To: <1392369319-24508-1-git-send-email-markwalters1009@gmail.com>
\r
51 References: <1392369319-24508-1-git-send-email-markwalters1009@gmail.com>
\r
52 X-BeenThere: notmuch@notmuchmail.org
\r
53 X-Mailman-Version: 2.1.13
\r
55 List-Id: "Use and development of the notmuch mail system."
\r
56 <notmuch.notmuchmail.org>
\r
57 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
58 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
59 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
60 List-Post: <mailto:notmuch@notmuchmail.org>
\r
61 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
62 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
63 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
64 X-List-Received-Date: Fri, 14 Feb 2014 09:15:35 -0000
\r
66 From: Austin Clements <amdragon@MIT.EDU>
\r
68 This was a little hack to test the feasibility of switching
\r
69 notmuch-tag-formats to use regexps with caching for performance. In
\r
70 the end it works fine and isn't particularly complex, though there
\r
73 1) We have to clear the cache somehow on changes to
\r
74 notmuch-tag-formats. I opted to use a defcustom :set plus some
\r
75 documentation telling people what to do if they change it directly
\r
76 from Elisp. This is less automatic than I would like, but I doubt
\r
77 people are changing this very often and I concluded that any machinery
\r
78 to automatically detect changes to notmuch-tag-formats would probably
\r
79 outweigh the benefits of caching. Alternatively, we could require
\r
80 search/show/tree buffers to "opt in" to caching when they start
\r
83 2) I spent way too long trying to use assoc-default before realizing
\r
84 this it just wouldn't work, since there's no way to distinguish a
\r
85 missing key from a present key with a null cdr. assoc* from cl works
\r
88 Performance-wise, the caching of regexp lookup makes this just as fast
\r
89 as assoc for unformatted tags (it would probably be faster if someone
\r
90 had a really big `notmuch-tag-formats') and the caching of eval
\r
91 results makes this much *faster* than the current code for formatted
\r
94 inbox (usec) unread (usec)
\r
97 regexp+caching: 0.4 0.4
\r
99 That said, even at 7.2 usec, tag formatting is still *very* fast
\r
100 (though regexp matching may get noticeably slower with larger
\r
101 `notmuch-tag-formats'). Tag formatting is nowhere near our top
\r
104 emacs/notmuch-tag.el | 75 +++++++++++++++++++++++++++++++++++--------------
\r
105 1 files changed, 53 insertions(+), 22 deletions(-)
\r
107 diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
\r
108 index 908e7ad..cb88fd5 100644
\r
109 --- a/emacs/notmuch-tag.el
\r
110 +++ b/emacs/notmuch-tag.el
\r
111 @@ -28,35 +28,56 @@
\r
113 (require 'notmuch-lib)
\r
115 +;; (notmuch-tag-clear-cache will be called by the defcustom
\r
116 +;; notmuch-tag-formats, so it has to be defined first.)
\r
118 +(defvar notmuch-tag--format-cache (make-hash-table :test 'equal)
\r
119 + "Cache of tag format lookup. Internal to `notmuch-tag-format-tag'.")
\r
121 +(defun notmuch-tag-clear-cache ()
\r
122 + "Clear the internal cache of tag formats.
\r
124 +This must be called after changes to `notmuch-tag-formats'."
\r
125 + (clrhash notmuch-tag--format-cache))
\r
127 (defcustom notmuch-tag-formats
\r
128 '(("unread" (propertize tag 'face '(:foreground "red")))
\r
129 ("flagged" (propertize tag 'face '(:foreground "blue"))
\r
130 (notmuch-tag-format-image-data tag (notmuch-tag-star-icon))))
\r
131 "Custom formats for individual tags.
\r
133 -This gives a list that maps from tag names to lists of formatting
\r
134 -expressions. The car of each element gives a tag name and the
\r
135 -cdr gives a list of Elisp expressions that modify the tag. If
\r
136 -the list is empty, the tag will simply be hidden. Otherwise,
\r
137 -each expression will be evaluated in order: for the first
\r
138 -expression, the variable `tag' will be bound to the tag name; for
\r
139 -each later expression, the variable `tag' will be bound to the
\r
140 -result of the previous expression. In this way, each expression
\r
141 -can build on the formatting performed by the previous expression.
\r
142 -The result of the last expression will displayed in place of the
\r
144 +This is an association list that maps from tag name regexps to
\r
145 +lists of formatting expressions. The first entry whose car
\r
146 +regexp-matches a tag will be used to format that tag. The regexp
\r
147 +is implicitly anchored, so to match a literal tag name, just use
\r
148 +that tag name (if it contains special regexp characters like
\r
149 +\".\" or \"*\", these have to be escaped). The cdr of the
\r
150 +matching entry gives a list of Elisp expressions that modify the
\r
151 +tag. If the list is empty, the tag will simply be hidden.
\r
152 +Otherwise, each expression will be evaluated in order: for the
\r
153 +first expression, the variable `tag' will be bound to the tag
\r
154 +name; for each later expression, the variable `tag' will be bound
\r
155 +to the result of the previous expression. In this way, each
\r
156 +expression can build on the formatting performed by the previous
\r
157 +expression. The result of the last expression will displayed in
\r
160 For example, to replace a tag with another string, simply use
\r
161 that string as a formatting expression. To change the foreground
\r
162 of a tag to red, use the expression
\r
163 (propertize tag 'face '(:foreground \"red\"))
\r
165 +After modifying this variable in Elisp, be sure to call
\r
166 +`notmuch-tag-clear-cache'. Modifying this via customize does
\r
167 +this automatically.
\r
169 See also `notmuch-tag-format-image', which can help replace tags
\r
172 :group 'notmuch-search
\r
173 :group 'notmuch-show
\r
174 - :type '(alist :key-type (string :tag "Tag")
\r
175 + :set (lambda (var val) (set-default var val) (notmuch-tag-clear-cache))
\r
176 + :type '(alist :key-type (regexp :tag "Tag")
\r
179 (radio :format "%v"
\r
180 @@ -137,16 +158,26 @@ This can be used with `notmuch-tag-format-image-data'."
\r
182 (defun notmuch-tag-format-tag (tag)
\r
183 "Format TAG by looking into `notmuch-tag-formats'."
\r
184 - (let ((formats (assoc tag notmuch-tag-formats)))
\r
186 - ((null formats) ;; - Tag not in `notmuch-tag-formats',
\r
187 - tag) ;; the format is the tag itself.
\r
188 - ((null (cdr formats)) ;; - Tag was deliberately hidden,
\r
189 - nil) ;; no format must be returned
\r
190 - (t ;; - Tag was found and has formats,
\r
191 - (let ((tag tag)) ;; we must apply all the formats.
\r
192 - (dolist (format (cdr formats) tag)
\r
193 - (setq tag (eval format))))))))
\r
194 + (let ((formatted (gethash tag notmuch-tag--format-cache 'missing)))
\r
195 + (when (eq formatted 'missing)
\r
198 + (assoc* tag notmuch-tag-formats
\r
199 + :test (lambda (tag key)
\r
200 + (and (eq (string-match key tag) 0)
\r
201 + (= (match-end 0) (length tag))))))))
\r
204 + ((null formats) ;; - Tag not in `notmuch-tag-formats',
\r
205 + tag) ;; the format is the tag itself.
\r
206 + ((null (cdr formats)) ;; - Tag was deliberately hidden,
\r
207 + nil) ;; no format must be returned
\r
208 + (t ;; - Tag was found and has formats,
\r
209 + (let ((tag tag)) ;; we must apply all the formats.
\r
210 + (dolist (format (cdr formats) tag)
\r
211 + (setq tag (eval format)))))))
\r
212 + (puthash tag formatted notmuch-tag--format-cache)))
\r
215 (defun notmuch-tag-format-tags (tags &optional face)
\r
216 "Return a string representing formatted TAGS."
\r