Re: [feature request] emacs: use `notmuch insert` for FCC
[notmuch-archives.git] / 56 / db3b6db4032192e91593fd71bd73e309664335
1 Return-Path: <dme@dme.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 53982431FBC\r
6         for <notmuch@notmuchmail.org>; Thu, 18 Feb 2010 01:44:17 -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: -2.318\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-2.318 tagged_above=-999 required=5 tests=[AWL=0.281,\r
12         BAYES_00=-2.599] autolearn=ham\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 oiEenqhIVFng for <notmuch@notmuchmail.org>;\r
16         Thu, 18 Feb 2010 01:44:15 -0800 (PST)\r
17 Received: from mail-ew0-f222.google.com (mail-ew0-f222.google.com\r
18         [209.85.219.222])\r
19         by olra.theworths.org (Postfix) with ESMTP id 948BE431FAE\r
20         for <notmuch@notmuchmail.org>; Thu, 18 Feb 2010 01:44:15 -0800 (PST)\r
21 Received: by ewy22 with SMTP id 22so3269242ewy.30\r
22         for <notmuch@notmuchmail.org>; Thu, 18 Feb 2010 01:44:14 -0800 (PST)\r
23 Received: by 10.213.43.9 with SMTP id u9mr1931376ebe.4.1266486254736;\r
24         Thu, 18 Feb 2010 01:44:14 -0800 (PST)\r
25 Received: from aw.hh.sledj.net (gmp-ea-fw-1b.sun.com [192.18.8.1])\r
26         by mx.google.com with ESMTPS id 28sm1597390eye.31.2010.02.18.01.44.12\r
27         (version=TLSv1/SSLv3 cipher=RC4-MD5);\r
28         Thu, 18 Feb 2010 01:44:13 -0800 (PST)\r
29 Received: by aw.hh.sledj.net (Postfix, from userid 1000)\r
30         id 912017031E; Thu, 18 Feb 2010 09:43:55 +0000 (GMT)\r
31 To: notmuch@notmuchmail.org\r
32 In-Reply-To: <1266415452-25108-2-git-send-email-dme@dme.org>\r
33 References: <1266415452-25108-1-git-send-email-dme@dme.org>\r
34         <1266415452-25108-2-git-send-email-dme@dme.org>\r
35 From: David Edmondson <dme@dme.org>\r
36 Date: Thu, 18 Feb 2010 09:43:55 +0000\r
37 Message-ID: <873a0yho9w.fsf@aw.hh.sledj.net>\r
38 MIME-Version: 1.0\r
39 Content-Type: multipart/mixed; boundary="=-=-="\r
40 Subject: Re: [notmuch] [PATCH 2/2] notmuch.el: Replace inline function calls\r
41  for body cleaning with a hook mechanism.\r
42 X-BeenThere: notmuch@notmuchmail.org\r
43 X-Mailman-Version: 2.1.13\r
44 Precedence: list\r
45 List-Id: "Use and development of the notmuch mail system."\r
46         <notmuch.notmuchmail.org>\r
47 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
48         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
49 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
50 List-Post: <mailto:notmuch@notmuchmail.org>\r
51 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
52 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
53         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
54 X-List-Received-Date: Thu, 18 Feb 2010 09:44:17 -0000\r
55 \r
56 --=-=-=\r
57 \r
58 On Wed, 17 Feb 2010 14:04:12 +0000, David Edmondson <dme@dme.org> wrote:\r
59 > In-lining every possible body cleaning function is difficult to\r
60 > maintain and doesn't allow users any flexibility. Rather, use a hook\r
61 > mechanism so that users can choose what cleaning takes place.\r
62 \r
63 Improved version attached, including a new washing function to clean up\r
64 citation blocks (suggested by Sebastian in #notmuch, though perhaps I\r
65 went a bit further than he intended).\r
66 \r
67 \r
68 --=-=-=\r
69 Content-Type: text/x-diff; charset=utf-8\r
70 Content-Disposition: inline;\r
71  filename=0001-notmuch.el-Replace-inline-function-calls-for-body-cl.patch\r
72 Content-Transfer-Encoding: quoted-printable\r
73 \r
74 >From 545e2a0936a19620bf4f91282ca2aca1da0504b7 Mon Sep 17 00:00:00 2001\r
75 From: David Edmondson <dme@dme.org>\r
76 Date: Wed, 17 Feb 2010 14:03:24 +0000\r
77 Subject: [PATCH] notmuch.el: Replace inline function calls for body cleanin=\r
78 g with a\r
79  hook mechanism.\r
80 \r
81 In-lining every possible body cleaning function is difficult to\r
82 maintain and doesn't allow users any flexibility. Rather, use a hook\r
83 mechanism so that users can choose what cleaning takes place.\r
84 \r
85 notmuch-washing.el: Sample cleaning functions.\r
86 ---\r
87  Makefile.local     |    6 ++-\r
88  notmuch-washing.el |  113 ++++++++++++++++++++++++++++++++++++++++++++++++=\r
89 ++++\r
90  notmuch.el         |  104 +++++++++++++++++++++++++-----------------------\r
91  3 files changed, 171 insertions(+), 52 deletions(-)\r
92  create mode 100644 notmuch-washing.el\r
93 \r
94 diff --git a/Makefile.local b/Makefile.local\r
95 index 0a1f203..7124af7 100644\r
96 --- a/Makefile.local\r
97 +++ b/Makefile.local\r
98 @@ -1,6 +1,6 @@\r
99  # -*- mode:makefile -*-\r
100 =20\r
101 -emacs: notmuch.elc coolj.elc\r
102 +emacs: notmuch.elc coolj.elc notmuch-washing.elc\r
103 =20\r
104  notmuch_client_srcs =3D                \\r
105         $(notmuch_compat_srcs)  \\r
106 @@ -46,6 +46,8 @@ install-emacs: install emacs\r
107         install -m0644 notmuch.elc $(DESTDIR)$(emacs_lispdir)\r
108         install -m0644 coolj.el $(DESTDIR)$(emacs_lispdir)\r
109         install -m0644 coolj.elc $(DESTDIR)$(emacs_lispdir)\r
110 +       install -m0644 notmuch-washing.el $(DESTDIR)$(emacs_lispdir)\r
111 +       install -m0644 notmuch-washing.elc $(DESTDIR)$(emacs_lispdir)\r
112 =20\r
113  install-desktop:\r
114         install -d $(DESTDIR)$(desktop_dir)\r
115 @@ -62,4 +64,4 @@ install-zsh:\r
116                 $(DESTDIR)$(zsh_completion_dir)/notmuch\r
117 =20\r
118  SRCS  :=3D $(SRCS) $(notmuch_client_srcs)\r
119 -CLEAN :=3D $(CLEAN) notmuch $(notmuch_client_modules) notmuch.elc coolj.el=\r
120 c notmuch.1.gz\r
121 +CLEAN :=3D $(CLEAN) notmuch $(notmuch_client_modules) notmuch.elc coolj.el=\r
122 c notmuch-washing.elc notmuch.1.gz\r
123 diff --git a/notmuch-washing.el b/notmuch-washing.el\r
124 new file mode 100644\r
125 index 0000000..fc7b257\r
126 --- /dev/null\r
127 +++ b/notmuch-washing.el\r
128 @@ -0,0 +1,113 @@\r
129 +;; notmuch-washing.el --- functions to clean body parts\r
130 +;;\r
131 +;; Copyright =C2=A9 David Edmondson\r
132 +;;\r
133 +;; This file is not (yet) part of Notmuch.\r
134 +;;\r
135 +;; Notmuch is free software: you can redistribute it and/or modify it\r
136 +;; under the terms of the GNU General Public License as published by\r
137 +;; the Free Software Foundation, either version 3 of the License, or\r
138 +;; (at your option) any later version.\r
139 +;;\r
140 +;; Notmuch is distributed in the hope that it will be useful, but\r
141 +;; WITHOUT ANY WARRANTY; without even the implied warranty of\r
142 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
143 +;; General Public License for more details.\r
144 +;;\r
145 +;; You should have received a copy of the GNU General Public License\r
146 +;; along with Notmuch.  If not, see <http://www.gnu.org/licenses/>.\r
147 +;;\r
148 +;; Authors: David Edmondson <dme@dme.org>\r
149 +\r
150 +(require 'coolj)\r
151 +\r
152 +;; Add these functions to `notmuch-show-markup-body-hook' using\r
153 +;; `add-hook'. Something like:\r
154 +\r
155 +;; (eval-after-load "notmuch"\r
156 +;;   '(progn\r
157 +;;      (require 'notmuch-washing)\r
158 +;;      (setq notmuch-show-markup-body-hook nil)\r
159 +;;      (add-hook 'notmuch-show-markup-body-hook 'notmuch-show-washing-coo=\r
160 lj t)\r
161 +;;      (add-hook 'notmuch-show-markup-body-hook 'notmuch-show-washing-cit=\r
162 ations t)\r
163 +;;      (add-hook 'notmuch-show-markup-body-hook 'notmuch-show-washing-com=\r
164 press-blanks t)\r
165 +;;      (add-hook 'notmuch-show-markup-body-hook 'notmuch-show-markup-cita=\r
166 tions t)\r
167 +;;      ))\r
168 +\r
169 +;; Note that the ordering of the functions is significant, given that\r
170 +;; later functions operate on the results of the earlier functions.\r
171 +\r
172 +(defun notmuch-show-washing-coolj (depth)\r
173 +  "Wrap text in the region whilst maintaining the correct prefix."\r
174 +  (coolj-wrap-region (point-min) (point-max)))\r
175 +\r
176 +;; Utility functions.\r
177 +(defun remove-prefix (depth)\r
178 +  (let ((prefix-regexp (format (format "^%%%ds" depth) "")))\r
179 +    (while (and (not (eobp))\r
180 +               (re-search-forward prefix-regexp nil t))\r
181 +      (replace-match "" nil nil)\r
182 +      (forward-line))))\r
183 +\r
184 +(defun insert-prefix (depth)\r
185 +  (let ((prefix (format (format "%%%ds" depth) "")))\r
186 +    (while (not (eobp))\r
187 +      (insert prefix)\r
188 +      (forward-line))))\r
189 +\r
190 +(defun notmuch-show-washing-compress-blanks (depth)\r
191 +  "Compress successive blank lines into one blank line."\r
192 +\r
193 +  ;; Algorithm derived from `article-strip-multiple-blank-lines' in\r
194 +  ;; `gnus-art.el'.\r
195 +\r
196 +  (goto-char (point-min))\r
197 +  (remove-prefix depth)\r
198 +\r
199 +  ;; Make all blank lines empty.\r
200 +  (goto-char (point-min))\r
201 +  (while (re-search-forward "^[ \t]+$" nil t)\r
202 +    (replace-match "" nil t))\r
203 +\r
204 +  ;; Replace multiple empty lines with a single empty line.\r
205 +  (goto-char (point-min))\r
206 +  (while (re-search-forward "\n\n\\(\n+\\)" nil t)\r
207 +    (delete-region (match-beginning 1) (match-end 1)))\r
208 +\r
209 +  (goto-char (point-min))\r
210 +  (insert-prefix depth))\r
211 +\r
212 +(defun notmuch-show-washing-citations (depth)\r
213 +  "Clean up citations."\r
214 +\r
215 +  (goto-char (point-min))\r
216 +  (remove-prefix depth)\r
217 +\r
218 +  ;; Remove lines of repeated citation leaders with no other content.\r
219 +  (goto-char (point-min))\r
220 +  (while (re-search-forward "\\(^>[> ]*\n\\)\\{2,\\}" nil t)\r
221 +    (replace-match "\\1"))\r
222 +\r
223 +  ;; Remove citation leaders standing alone before a block of cited\r
224 +  ;; text.\r
225 +  (goto-char (point-min))\r
226 +  (while (re-search-forward "\\(\n\\|^[^>].*\\)\n\\(^>[> ]*\n\\)" nil t)\r
227 +    (replace-match "\\1\n"))\r
228 +\r
229 +  ;; Remove citation trailers standing alone after a block of cited\r
230 +  ;; text.\r
231 +  (goto-char (point-min))\r
232 +  (while (re-search-forward "\\(^>[> ]*\n\\)\\(^$\\|^[^>].*\\)" nil t)\r
233 +    (replace-match "\\2"))\r
234 +\r
235 +  ;; Remove blank lines between "Bill wrote:" and the citation.\r
236 +  (goto-char (point-min))\r
237 +  (while (re-search-forward "^\\([^>].*\\):\n\n>" nil t)\r
238 +    (replace-match "\\1:\n>"))\r
239 +\r
240 +  (goto-char (point-min))\r
241 +  (insert-prefix depth))\r
242 +\r
243 +;;\r
244 +\r
245 +(provide 'notmuch-washing)\r
246 diff --git a/notmuch.el b/notmuch.el\r
247 index 040fb5e..9d86a3f 100644\r
248 --- a/notmuch.el\r
249 +++ b/notmuch.el\r
250 @@ -50,7 +50,6 @@\r
251  (require 'cl)\r
252  (require 'mm-view)\r
253  (require 'message)\r
254 -(require 'coolj)\r
255 =20\r
256  (defvar notmuch-show-mode-map\r
257    (let ((map (make-sparse-keymap)))\r
258 @@ -157,6 +156,12 @@ collapse remaining lines into a button.")\r
259  (defvar notmuch-show-signatures-visible nil)\r
260  (defvar notmuch-show-headers-visible nil)\r
261 =20\r
262 +(defun notmuch-show-markup-body-hook '(notmuch-show-markup-citations)\r
263 +  "List of functions used to clean up body parts.\r
264 +\r
265 +Each is passed one argument: the indentation depth of the region\r
266 +to be washed.")\r
267 +\r
268  ; XXX: This should be a generic function in emacs somewhere, not here\r
269  (defun point-invisible-p ()\r
270    "Return whether the character at point is invisible.\r
271 @@ -703,52 +708,48 @@ is what to put on the button."\r
272                      :type button-type)\r
273        )))\r
274 =20\r
275 -\r
276 -(defun notmuch-show-markup-citations-region (beg end depth)\r
277 -  "Markup citations, and up to one signature in the given region"\r
278 -  ;; it would be nice if the untabify was not required, but\r
279 -  ;; that would require notmuch to indent with spaces.\r
280 -  (untabify beg end)\r
281 -  (let ((citation-regexp (notmuch-show-citation-regexp depth))\r
282 -       (signature-regexp (concat (format "^[[:space:]]\\{%d\\}" depth)\r
283 -                                 notmuch-show-signature-regexp))\r
284 -       (indent (concat "\n" (make-string depth ? ))))\r
285 -    (goto-char beg)\r
286 -    (beginning-of-line)\r
287 -    (while (and (< (point) end)\r
288 -               (re-search-forward citation-regexp end t))\r
289 -      (let* ((cite-start (match-beginning 0))\r
290 -            (cite-end  (match-end 0))\r
291 -            (cite-lines (count-lines cite-start cite-end)))\r
292 -       (overlay-put (make-overlay cite-start cite-end) 'face 'message-cited-text=\r
293 -face)\r
294 -       (when (> cite-lines (1+ (+ notmuch-show-citation-lines-prefix notmuch-sho=\r
295 w-citation-lines-suffix)))\r
296 -         (goto-char cite-start)\r
297 -         (forward-line notmuch-show-citation-lines-prefix)\r
298 -         (let ((hidden-start (point)))\r
299 -           (goto-char cite-end)\r
300 -           (forward-line (- notmuch-show-citation-lines-suffix))\r
301 -           (notmuch-show-region-to-button\r
302 -            hidden-start (point)\r
303 -            "citation"\r
304 -            indent\r
305 -            (format notmuch-show-citation-button-format\r
306 -                    (- cite-lines notmuch-show-citation-lines-prefix notmuch-show-citat=\r
307 ion-lines-suffix))\r
308 -            )))))\r
309 -    (if (and (< (point) end)\r
310 -            (re-search-forward signature-regexp end t))\r
311 -       (let* ((sig-start (match-beginning 0))\r
312 -              (sig-end (match-end 0))\r
313 -              (sig-lines (1- (count-lines sig-start end))))\r
314 -         (if (<=3D sig-lines notmuch-show-signature-lines-max)\r
315 -             (progn\r
316 -               (overlay-put (make-overlay sig-start end) 'face 'message-cited-text-face)\r
317 -               (notmuch-show-region-to-button\r
318 -                sig-start\r
319 -                end\r
320 -                "signature"\r
321 -                indent\r
322 -                (format notmuch-show-signature-button-format sig-lines)\r
323 -                )))))))\r
324 +(defun notmuch-show-markup-citations (depth)\r
325 +  "Markup citations, and up to one signature in the buffer."\r
326 +    (let ((citation-regexp (notmuch-show-citation-regexp depth))\r
327 +         (signature-regexp (concat (format "^[[:space:]]\\{%d\\}" depth)\r
328 +                                   notmuch-show-signature-regexp))\r
329 +         (indent (concat "\n" (make-string depth ? ))))\r
330 +      (goto-char (point-min))\r
331 +      (beginning-of-line)\r
332 +      (while (and (< (point) (point-max))\r
333 +                 (re-search-forward citation-regexp nil t))\r
334 +       (let* ((cite-start (match-beginning 0))\r
335 +              (cite-end        (match-end 0))\r
336 +              (cite-lines (count-lines cite-start cite-end)))\r
337 +         (overlay-put (make-overlay cite-start cite-end) 'face 'message-cited-te=\r
338 xt-face)\r
339 +         (when (> cite-lines (1+ (+ notmuch-show-citation-lines-prefix notmuch-s=\r
340 how-citation-lines-suffix)))\r
341 +           (goto-char cite-start)\r
342 +           (forward-line notmuch-show-citation-lines-prefix)\r
343 +           (let ((hidden-start (point)))\r
344 +             (goto-char cite-end)\r
345 +             (forward-line (- notmuch-show-citation-lines-suffix))\r
346 +             (notmuch-show-region-to-button\r
347 +              hidden-start (point)\r
348 +              "citation"\r
349 +              indent\r
350 +              (format notmuch-show-citation-button-format\r
351 +                      (- cite-lines notmuch-show-citation-lines-prefix notmuch-show-cit=\r
352 ation-lines-suffix))\r
353 +              )))))\r
354 +      (if (and (not (eobp))\r
355 +              (re-search-forward signature-regexp nil t))\r
356 +         (let* ((sig-start (match-beginning 0))\r
357 +                (sig-end (match-end 0))\r
358 +                (sig-lines (1- (count-lines sig-start (point-max)))))\r
359 +           (if (<=3D sig-lines notmuch-show-signature-lines-max)\r
360 +               (progn\r
361 +                 (overlay-put (make-overlay sig-start (point-max)) 'face 'message-cited=\r
362 -text-face)\r
363 +                 (notmuch-show-region-to-button\r
364 +                  sig-start\r
365 +                  (point-max)\r
366 +                  "signature"\r
367 +                  indent\r
368 +                  (format notmuch-show-signature-button-format sig-lines)\r
369 +                  )))))))\r
370 =20\r
371  (defun notmuch-show-markup-part (beg end depth)\r
372    (if (re-search-forward notmuch-show-buttonize-begin-regexp nil t)\r
373 @@ -791,9 +792,12 @@ is what to put on the button."\r
374                            (mm-display-part mime-message))))\r
375                  )\r
376               (if (equal mime-type "text/plain")\r
377 -                 (progn\r
378 -                   (coolj-wrap-region beg end)\r
379 -                   (notmuch-show-markup-citations-region beg end depth)))\r
380 +                 (save-restriction\r
381 +                   (narrow-to-region beg end)\r
382 +                   ;; it would be nice if the untabify was not required, but\r
383 +                   ;; that would require notmuch to indent with spaces.\r
384 +                   (untabify (point-min) (point-max))\r
385 +                   (run-hook-with-args 'notmuch-show-markup-body-hook depth)))\r
386                ; Advance to the next part (if any) (so the outer loop can\r
387                ; determine whether we've left the current message.\r
388                (if (re-search-forward notmuch-show-buttonize-begin-regexp n=\r
389 il t)\r
390 --=20\r
391 1.6.6.1\r
392 \r
393 \r
394 --=-=-=\r
395 \r
396 \r
397 dme.\r
398 -- \r
399 David Edmondson, http://dme.org\r
400 \r
401 --=-=-=--\r