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 EC88A4196F2
\r
6 for <notmuch@notmuchmail.org>; Thu, 22 Apr 2010 05:26:32 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org
\r
11 X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5
\r
12 tests=[BAYES_00=-1.9] 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 cOMY9gVaAMjf for <notmuch@notmuchmail.org>;
\r
16 Thu, 22 Apr 2010 05:26:29 -0700 (PDT)
\r
17 Received: from mail-ww0-f53.google.com (mail-ww0-f53.google.com
\r
18 [74.125.82.53]) by olra.theworths.org (Postfix) with ESMTP id 87EB0431FC1 for
\r
19 <notmuch@notmuchmail.org>; Thu, 22 Apr 2010 05:26:29 -0700 (PDT)
\r
20 Received: by wwb28 with SMTP id 28so2188944wwb.26
\r
21 for <notmuch@notmuchmail.org>; Thu, 22 Apr 2010 05:26:28 -0700 (PDT)
\r
22 Received: by 10.216.157.202 with SMTP id o52mr1828214wek.212.1271939169229;
\r
23 Thu, 22 Apr 2010 05:26:09 -0700 (PDT)
\r
24 Received: from ut.hh.sledj.net (gmp-ea-fw-1.sun.com [192.18.1.36])
\r
25 by mx.google.com with ESMTPS id r29sm24782475wbv.15.2010.04.22.05.26.07
\r
26 (version=TLSv1/SSLv3 cipher=RC4-MD5);
\r
27 Thu, 22 Apr 2010 05:26:07 -0700 (PDT)
\r
28 Received: by ut.hh.sledj.net (Postfix, from userid 1000)
\r
29 id 6A7BA594118; Thu, 22 Apr 2010 13:26:07 +0100 (BST)
\r
30 From: David Edmondson <dme@dme.org>
\r
31 To: notmuch@notmuchmail.org
\r
32 Subject: [PATCH] emacs: Add more functions to clean up text/plain parts
\r
33 Date: Thu, 22 Apr 2010 13:26:06 +0100
\r
34 Message-Id: <1271939166-24100-1-git-send-email-dme@dme.org>
\r
35 X-Mailer: git-send-email 1.7.0
\r
36 X-BeenThere: notmuch@notmuchmail.org
\r
37 X-Mailman-Version: 2.1.13
\r
39 List-Id: "Use and development of the notmuch mail system."
\r
40 <notmuch.notmuchmail.org>
\r
41 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,
\r
42 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
43 List-Archive: <http://notmuchmail.org/pipermail/notmuch>
\r
44 List-Post: <mailto:notmuch@notmuchmail.org>
\r
45 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
46 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,
\r
47 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
48 X-List-Received-Date: Thu, 22 Apr 2010 12:26:33 -0000
\r
51 - notmuch-wash-wrap-long-lines: Wrap lines longer than the width of
\r
52 the current window whilst maintaining any citation prefix.
\r
53 - notmuch-wash-tidy-citations: Tidy up citations by:
\r
54 - compress repeated otherwise blank citation lines,
\r
55 - remove otherwise blank citation lines at the head and tail of a
\r
56 citation and remove blank lines between attribution statements and
\r
58 - notmuch-wash-compress-blanks: Compress repeated blank lines and
\r
59 remove leading and trailing blank lines.
\r
61 Enable `notmuch-wash-tidy-citations' and
\r
62 `notmuch-wash-compress-blanks' by default by adding them to
\r
63 `notmuch-show-insert-text/plain-hook'. `notmuch-wash-wrap-long-lines'
\r
64 is not enabled by default.
\r
66 If `notmuch-wash-wrap-long-lines' is enabled, word wrapping of the
\r
67 buffer leads to an unappealing display of text, so provide a function
\r
68 to disable it and add it to the list of `notmuch-show-mode' hook
\r
72 This is a small variant on the previous version of the patch. The
\r
73 wrapping of long lines is not enabled by default - it's simply an
\r
74 option in the customise interface.
\r
76 emacs/Makefile.local | 3 +-
\r
77 emacs/coolj.el | 145 +++++++++++++++++++++++++++++++++++++++++++++++++
\r
78 emacs/notmuch-show.el | 25 +++++++--
\r
79 emacs/notmuch-wash.el | 72 ++++++++++++++++++++++++-
\r
80 4 files changed, 239 insertions(+), 6 deletions(-)
\r
81 create mode 100644 emacs/coolj.el
\r
83 diff --git a/emacs/Makefile.local b/emacs/Makefile.local
\r
84 index 7537c3d..ce37ca2 100644
\r
85 --- a/emacs/Makefile.local
\r
86 +++ b/emacs/Makefile.local
\r
87 @@ -9,7 +9,8 @@ emacs_sources := \
\r
88 $(dir)/notmuch-wash.el \
\r
89 $(dir)/notmuch-hello.el \
\r
90 $(dir)/notmuch-mua.el \
\r
91 - $(dir)/notmuch-address.el
\r
92 + $(dir)/notmuch-address.el \
\r
96 $(dir)/notmuch-logo.png
\r
97 diff --git a/emacs/coolj.el b/emacs/coolj.el
\r
98 new file mode 100644
\r
99 index 0000000..60af60a
\r
101 +++ b/emacs/coolj.el
\r
103 +;;; coolj.el --- automatically wrap long lines -*- coding:utf-8 -*-
\r
105 +;; Copyright (C) 2000, 2001, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
\r
107 +;; Authors: Kai Grossjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
\r
108 +;; Alex Schroeder <alex@gnu.org>
\r
109 +;; Chong Yidong <cyd@stupidchicken.com>
\r
110 +;; Maintainer: David Edmondson <dme@dme.org>
\r
111 +;; Keywords: convenience, wp
\r
113 +;; This file is not part of GNU Emacs.
\r
115 +;; GNU Emacs is free software: you can redistribute it and/or modify
\r
116 +;; it under the terms of the GNU General Public License as published by
\r
117 +;; the Free Software Foundation, either version 3 of the License, or
\r
118 +;; (at your option) any later version.
\r
120 +;; GNU Emacs is distributed in the hope that it will be useful,
\r
121 +;; but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
122 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
123 +;; GNU General Public License for more details.
\r
125 +;; You should have received a copy of the GNU General Public License
\r
126 +;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
\r
130 +;;; This is a simple derivative of some functionality from
\r
131 +;;; `longlines.el'. The key difference is that this version will
\r
132 +;;; insert a prefix at the head of each wrapped line. The prefix is
\r
133 +;;; calculated from the originating long line.
\r
135 +;;; No minor-mode is provided, the caller is expected to call
\r
136 +;;; `coolj-wrap-region' to wrap the region of interest.
\r
140 +(defgroup coolj nil
\r
141 + "Wrapping of long lines with prefix."
\r
144 +(defcustom coolj-wrap-follows-window-size t
\r
145 + "Non-nil means wrap text to the window size.
\r
146 +Otherwise respect `fill-column'."
\r
150 +(defcustom coolj-line-prefix-regexp "^\\(>+ \\)*"
\r
151 + "Regular expression that matches line prefixes."
\r
155 +(defvar coolj-wrap-point nil)
\r
157 +(make-variable-buffer-local 'coolj-wrap-point)
\r
159 +(defun coolj-determine-prefix ()
\r
160 + "Determine the prefix for the current line."
\r
162 + (beginning-of-line)
\r
163 + (if (re-search-forward coolj-line-prefix-regexp nil t)
\r
164 + (buffer-substring (match-beginning 0) (match-end 0))
\r
167 +(defun coolj-wrap-buffer ()
\r
168 + "Wrap the current buffer."
\r
169 + (coolj-wrap-region (point-min) (point-max)))
\r
171 +(defun coolj-wrap-region (beg end)
\r
172 + "Wrap each successive line, starting with the line before BEG.
\r
173 +Stop when we reach lines after END that don't need wrapping, or the
\r
174 +end of the buffer."
\r
175 + (setq fill-column (if coolj-wrap-follows-window-size
\r
178 + (let ((mod (buffer-modified-p)))
\r
179 + (setq coolj-wrap-point (point))
\r
181 + (forward-line -1)
\r
182 + ;; Two successful coolj-wrap-line's in a row mean successive
\r
183 + ;; lines don't need wrapping.
\r
184 + (while (null (and (coolj-wrap-line)
\r
186 + (and (>= (point) end)
\r
187 + (coolj-wrap-line))))))
\r
188 + (goto-char coolj-wrap-point)
\r
189 + (set-buffer-modified-p mod)))
\r
191 +(defun coolj-wrap-line ()
\r
192 + "If the current line needs to be wrapped, wrap it and return nil.
\r
193 +If wrapping is performed, point remains on the line. If the line does
\r
194 +not need to be wrapped, move point to the next line and return t."
\r
195 + (let ((prefix (coolj-determine-prefix)))
\r
196 + (if (coolj-set-breakpoint prefix)
\r
198 + (insert-before-markers ?\n)
\r
199 + (backward-char 1)
\r
202 + (insert-before-markers prefix)
\r
207 +(defun coolj-set-breakpoint (prefix)
\r
208 + "Place point where we should break the current line, and return t.
\r
209 +If the line should not be broken, return nil; point remains on the
\r
211 + (move-to-column fill-column)
\r
212 + (if (and (re-search-forward "[^ ]" (line-end-position) 1)
\r
213 + (> (current-column) fill-column))
\r
214 + ;; This line is too long. Can we break it?
\r
215 + (or (coolj-find-break-backward prefix)
\r
216 + (progn (move-to-column fill-column)
\r
217 + (coolj-find-break-forward)))))
\r
219 +(defun coolj-find-break-backward (prefix)
\r
220 + "Move point backward to the first available breakpoint and return t.
\r
221 +If no breakpoint is found, return nil."
\r
222 + (let ((end-of-prefix (+ (line-beginning-position) (length prefix))))
\r
223 + (and (search-backward " " end-of-prefix 1)
\r
225 + (skip-chars-backward " " end-of-prefix)
\r
227 + (progn (forward-char 1)
\r
228 + (if (and fill-nobreak-predicate
\r
229 + (run-hook-with-args-until-success
\r
230 + 'fill-nobreak-predicate))
\r
231 + (progn (skip-chars-backward " " end-of-prefix)
\r
232 + (coolj-find-break-backward prefix))
\r
235 +(defun coolj-find-break-forward ()
\r
236 + "Move point forward to the first available breakpoint and return t.
\r
237 +If no break point is found, return nil."
\r
238 + (and (search-forward " " (line-end-position) 1)
\r
239 + (progn (skip-chars-forward " " (line-end-position))
\r
241 + (if (and fill-nobreak-predicate
\r
242 + (run-hook-with-args-until-success
\r
243 + 'fill-nobreak-predicate))
\r
244 + (coolj-find-break-forward)
\r
248 diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
\r
249 index d01bf36..cd859f0 100644
\r
250 --- a/emacs/notmuch-show.el
\r
251 +++ b/emacs/notmuch-show.el
\r
252 @@ -46,17 +46,34 @@ collapsed will change.")
\r
253 "A list of functions called to decorate the headers listed in
\r
254 `notmuch-show-headers'.")
\r
256 -(defvar notmuch-show-hook '(notmuch-show-pretty-hook)
\r
257 +(defcustom notmuch-show-hook '(notmuch-show-pretty-hook)
\r
258 "A list of functions called after populating a
\r
259 -`notmuch-show' buffer.")
\r
261 -(defvar notmuch-show-insert-text/plain-hook '(notmuch-wash-text/plain-citations)
\r
262 - "A list of functions called to clean up text/plain body parts.")
\r
263 +`notmuch-show' buffer."
\r
266 + :options '(notmuch-show-pretty-hook
\r
267 + notmuch-show-turn-off-word-wrap))
\r
269 +(defcustom notmuch-show-insert-text/plain-hook
\r
270 + '(notmuch-wash-tidy-citations
\r
271 + notmuch-wash-compress-blanks
\r
272 + notmuch-wash-markup-citations)
\r
273 + "A list of functions called to clean up text/plain body parts."
\r
276 + :options '(notmuch-wash-wrap-long-lines
\r
277 + notmuch-wash-tidy-citations
\r
278 + notmuch-wash-compress-blanks
\r
279 + notmuch-wash-markup-citations))
\r
281 (defun notmuch-show-pretty-hook ()
\r
282 (goto-address-mode 1)
\r
283 (visual-line-mode))
\r
285 +(defun notmuch-show-turn-off-word-wrap ()
\r
286 + ;; `toggle-word-wrap' outputs a message, which is distracting.
\r
287 + (setq word-wrap nil))
\r
289 (defmacro with-current-notmuch-show-message (&rest body)
\r
290 "Evaluate body with current buffer set to the text of current message"
\r
292 diff --git a/emacs/notmuch-wash.el b/emacs/notmuch-wash.el
\r
293 index 54a380a..fe33819 100644
\r
294 --- a/emacs/notmuch-wash.el
\r
295 +++ b/emacs/notmuch-wash.el
\r
297 ;; notmuch-wash.el --- cleaning up message bodies
\r
299 ;; Copyright © Carl Worth
\r
300 +;; Copyright © David Edmondson
\r
302 ;; This file is part of Notmuch.
\r
305 ;; along with Notmuch. If not, see <http://www.gnu.org/licenses/>.
\r
307 ;; Authors: Carl Worth <cworth@cworth.org>
\r
308 +;; David Edmondson <dme@dme.org>
\r
314 (defvar notmuch-wash-signature-regexp
\r
315 "^\\(-- ?\\|_+\\)$"
\r
316 @@ -104,7 +110,7 @@ is what to put on the button."
\r
317 'invisibility-spec invis-spec
\r
318 :type button-type))))
\r
320 -(defun notmuch-wash-text/plain-citations (depth)
\r
321 +(defun notmuch-wash-markup-citations (depth)
\r
322 "Markup citations, and up to one signature in the buffer."
\r
323 (goto-char (point-min))
\r
324 (beginning-of-line)
\r
325 @@ -147,4 +153,68 @@ is what to put on the button."
\r
329 +(defun notmuch-wash-compress-blanks (depth)
\r
330 + "Compress successive blank lines into one blank line. Remove
\r
331 +any leading or trailing blank lines."
\r
333 + ;; Algorithm derived from `article-strip-multiple-blank-lines' in
\r
334 + ;; `gnus-art.el'.
\r
336 + ;; Make all blank lines empty.
\r
337 + (goto-char (point-min))
\r
338 + (while (re-search-forward "^[[:space:]\t]+$" nil t)
\r
339 + (replace-match "" nil t))
\r
341 + ;; Replace multiple empty lines with a single empty line.
\r
342 + (goto-char (point-min))
\r
343 + (while (re-search-forward "^\n\\(\n+\\)" nil t)
\r
344 + (delete-region (match-beginning 1) (match-end 1)))
\r
346 + ;; Remove a leading blank line.
\r
347 + (goto-char (point-min))
\r
348 + (if (looking-at "\n")
\r
349 + (delete-region (match-beginning 0) (match-end 0)))
\r
351 + ;; Remove a trailing blank line.
\r
352 + (goto-char (point-max))
\r
353 + (if (looking-at "\n")
\r
354 + (delete-region (match-beginning 0) (match-end 0))))
\r
358 +(defun notmuch-wash-tidy-citations (depth)
\r
359 + "Clean up citations."
\r
361 + ;; Remove lines of repeated citation leaders with no other content.
\r
362 + (goto-char (point-min))
\r
363 + (while (re-search-forward "\\(^>[> ]*\n\\)\\{2,\\}" nil t)
\r
364 + (replace-match "\\1"))
\r
366 + ;; Remove citation leaders standing alone before a block of cited
\r
368 + (goto-char (point-min))
\r
369 + (while (re-search-forward "\\(\n\\|^[^>].*\\)\n\\(^>[> ]*\n\\)" nil t)
\r
370 + (replace-match "\\1\n"))
\r
372 + ;; Remove citation trailers standing alone after a block of cited
\r
374 + (goto-char (point-min))
\r
375 + (while (re-search-forward "\\(^>[> ]*\n\\)\\(^$\\|^[^>].*\\)" nil t)
\r
376 + (replace-match "\\2"))
\r
378 + ;; Remove blank lines between "Bill wrote:" and the citation.
\r
379 + (goto-char (point-min))
\r
380 + (while (re-search-forward "^\\([^>].*\\):\n\n>" nil t)
\r
381 + (replace-match "\\1:\n>")))
\r
385 +(defun notmuch-wash-wrap-long-lines (depth)
\r
386 + "Wrap text in the region whilst maintaining the correct prefix."
\r
387 + (let ((coolj-wrap-follows-window-size nil)
\r
388 + (fill-column (- (window-width) depth)))
\r
389 + (coolj-wrap-region (point-min) (point-max))))
\r
393 (provide 'notmuch-wash)
\r