aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarl Fogel1996-05-08 02:38:37 +0000
committerKarl Fogel1996-05-08 02:38:37 +0000
commit1747a1941c1229b41e22ba249ca365dc0ec99d1b (patch)
tree4430c9824c100ddb21e467388c2ceb562777bd51
parenta15269c0d04259277ff1d9d6a6dac8b60184ece3 (diff)
downloademacs-1747a1941c1229b41e22ba249ca365dc0ec99d1b.tar.gz
emacs-1747a1941c1229b41e22ba249ca365dc0ec99d1b.zip
(mail-hist-version): upped to 1.3.4.
(mail-hist-put-headers-into-history): wrap relevant body in a `save-excursion'. (mail-hist-add-header-contents-to-ring): doc fix. Use `mail-hist-text-size-limit' directly. (mail-hist-text-size-limit): doc fix. (mail-hist-text-too-long-p): removed, we don't need this func. (mail-hist-forward-header): move to point just after colon, don't try to treat whitespace specially. (mail-hist-next-or-previous-input): new func, abstracts two funcs below. Error informatively if not in a header. Compensate for the extra SPACE char in "virgin" headers. (mail-hist-next-input): just call above. (mail-hist-previous-input): same. (mail-hist-header-virgin-p): new func.
-rw-r--r--lisp/mail/mail-hist.el206
1 files changed, 108 insertions, 98 deletions
diff --git a/lisp/mail/mail-hist.el b/lisp/mail/mail-hist.el
index 25bdcc2e55f..eb131df4496 100644
--- a/lisp/mail/mail-hist.el
+++ b/lisp/mail/mail-hist.el
@@ -1,9 +1,9 @@
1;;; mail-hist.el --- Headers and message body history for outgoing mail. 1;;; mail-hist.el --- Headers and message body history for outgoing mail.
2
3;; Copyright (C) 1994 Free Software Foundation, Inc. 2;; Copyright (C) 1994 Free Software Foundation, Inc.
4 3
5;; Author: Karl Fogel <kfogel@cs.oberlin.edu> 4;; Author: Karl Fogel <kfogel@cs.oberlin.edu>
6;; Created: March, 1994 5;; Created: March, 1994
6;; Version: See variable `mail-hist-version'.
7;; Keywords: mail, history 7;; Keywords: mail, history
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
@@ -18,11 +18,6 @@
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details. 19;; GNU General Public License for more details.
20 20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
25
26;;; Commentary: 21;;; Commentary:
27 22
28;; You should have received a copy of the GNU General Public License 23;; You should have received a copy of the GNU General Public License
@@ -60,6 +55,9 @@
60;;; Code: 55;;; Code:
61(require 'ring) 56(require 'ring)
62 57
58(defconst mail-hist-version "1.3.4"
59 "The version number of this mail-hist package.")
60
63;;;###autoload 61;;;###autoload
64(defun mail-hist-define-keys () 62(defun mail-hist-define-keys ()
65 "Define keys for accessing mail header history. For use in hooks." 63 "Define keys for accessing mail header history. For use in hooks."
@@ -67,9 +65,13 @@
67 (local-set-key "\M-n" 'mail-hist-next-input)) 65 (local-set-key "\M-n" 'mail-hist-next-input))
68 66
69;;;###autoload 67;;;###autoload
70(defun mail-hist-enable () 68(add-hook 'mail-mode-hook 'mail-hist-define-keys)
71 (add-hook 'mail-mode-hook 'mail-hist-define-keys) 69
72 (add-hook 'mail-send-hook 'mail-hist-put-headers-into-history)) 70;;;###autoload
71(add-hook 'vm-mail-mode-hook 'mail-hist-define-keys)
72
73;;;###autoload
74(add-hook 'mail-send-hook 'mail-hist-put-headers-into-history)
73 75
74(defvar mail-hist-header-ring-alist nil 76(defvar mail-hist-header-ring-alist nil
75 "Alist of form (header-name . history-ring). 77 "Alist of form (header-name . history-ring).
@@ -100,16 +102,14 @@ Oldest elements are dumped first.")
100Returns nil if not in a header, implying that point is in the body of 102Returns nil if not in a header, implying that point is in the body of
101the message." 103the message."
102 (if (save-excursion 104 (if (save-excursion
103 (re-search-backward (concat "^" (regexp-quote mail-header-separator) 105 (re-search-backward
104 "$") 106 (concat "^" (regexp-quote mail-header-separator)) nil t))
105 nil t))
106 nil ; then we are in the body of the message 107 nil ; then we are in the body of the message
107 (save-excursion 108 (save-excursion
108 (let* ((body-start ; limit possibility of false headers 109 (let* ((body-start ; limit possibility of false headers
109 (save-excursion 110 (save-excursion
110 (re-search-forward 111 (re-search-forward
111 (concat "^" (regexp-quote mail-header-separator) "$") 112 (concat "^" (regexp-quote mail-header-separator)) nil t)))
112 nil t)))
113 (name-start 113 (name-start
114 (re-search-backward mail-hist-header-regexp nil t)) 114 (re-search-backward mail-hist-header-regexp nil t))
115 (name-end 115 (name-end
@@ -122,42 +122,40 @@ the message."
122(defsubst mail-hist-forward-header (count) 122(defsubst mail-hist-forward-header (count)
123 "Move forward COUNT headers (backward if COUNT is negative). 123 "Move forward COUNT headers (backward if COUNT is negative).
124If last/first header is encountered first, stop there and returns 124If last/first header is encountered first, stop there and returns
125nil. 125nil.
126 126Places point directly after the colon."
127Places point on the first non-whitespace on the line following the 127 (let ((boundary
128colon after the header name, or on the second space following that if 128 (save-excursion
129the header is empty." 129 (if (re-search-forward
130 (let ((boundary (save-excursion 130 (concat "^" (regexp-quote mail-header-separator)) nil t)
131 (re-search-forward 131 (progn
132 (concat "^" (regexp-quote mail-header-separator) "$") 132 (beginning-of-line)
133 nil t)))) 133 (1- (point)))
134 (and 134 nil))))
135 boundary 135
136 (let ((unstopped t)) 136 (if boundary
137 (setq boundary (save-excursion 137 (let ((unstopped t))
138 (goto-char boundary) 138 (if (> count 0)
139 (beginning-of-line) 139 ;; Moving forward.
140 (1- (point)))) 140 (while (> count 0)
141 (if (> count 0) 141 (setq
142 (while (> count 0) 142 unstopped
143 (setq 143 (re-search-forward mail-hist-header-regexp boundary t))
144 unstopped 144 (setq count (1- count)))
145 (re-search-forward mail-hist-header-regexp boundary t)) 145 ;; Else moving backward.
146 (setq count (1- count))) 146 ;; Decrement because the current header will match too.
147 ;; because the current header will match too. 147 (setq count (1- count))
148 (setq count (1- count)) 148 ;; count is negative
149 ;; count is negative 149 (while (< count 0)
150 (while (< count 0) 150 (setq
151 (setq 151 unstopped
152 unstopped 152 (re-search-backward mail-hist-header-regexp nil t))
153 (re-search-backward mail-hist-header-regexp nil t)) 153 (setq count (1+ count)))
154 (setq count (1+ count))) 154 ;; We end up behind the header, so must move to the front.
155 ;; we end up behind the header, so must move to the front 155 (re-search-forward mail-hist-header-regexp boundary t))
156 (re-search-forward mail-hist-header-regexp boundary t)) 156 ;; Poof! Now we're sitting just past the colon. Finito.
157 ;; Now we are right after the colon 157 ;; Return nil if didn't go as far as asked, otherwise point
158 (and (looking-at "\\s-") (forward-char 1)) 158 unstopped))))
159 ;; return nil if didn't go as far as asked, otherwise point
160 unstopped))))
161 159
162(defsubst mail-hist-beginning-of-header () 160(defsubst mail-hist-beginning-of-header ()
163 "Move to the start of the current header. 161 "Move to the start of the current header.
@@ -176,7 +174,7 @@ colon, or just after the colon if it is not followed by whitespace."
176 (let ((start (point))) 174 (let ((start (point)))
177 (or (mail-hist-forward-header 1) 175 (or (mail-hist-forward-header 1)
178 (re-search-forward 176 (re-search-forward
179 (concat "^" (regexp-quote mail-header-separator) "$"))) 177 (concat "^" (regexp-quote mail-header-separator))))
180 (beginning-of-line) 178 (beginning-of-line)
181 (buffer-substring start (1- (point)))))) 179 (buffer-substring start (1- (point))))))
182 180
@@ -186,24 +184,26 @@ HEADER is a string without the colon."
186 (setq header (downcase header)) 184 (setq header (downcase header))
187 (cdr (assoc header mail-hist-header-ring-alist))) 185 (cdr (assoc header mail-hist-header-ring-alist)))
188 186
187
189(defvar mail-hist-text-size-limit nil 188(defvar mail-hist-text-size-limit nil
190 "*Don't store any header or body with more than this many characters. 189 "*Don't store any header or body with more than this many
191If the value is nil, that means no limit on text size.") 190characters, plus one. Nil means there will be no limit on text size.")
192 191
193(defun mail-hist-text-too-long-p (text)
194 "Return t if TEXT does not exceed mail-hist's size limit.
195The variable `mail-hist-text-size-limit' defines this limit."
196 (if mail-hist-text-size-limit
197 (> (length text) mail-hist-text-size-limit)))
198 192
199(defsubst mail-hist-add-header-contents-to-ring (header &optional contents) 193(defsubst mail-hist-add-header-contents-to-ring (header &optional contents)
200 "Add the contents of HEADER to the header history ring. 194 "Add the contents of the current HEADER to the header history ring.
195HEADER is a string; it will be downcased.
201Optional argument CONTENTS is a string which will be the contents 196Optional argument CONTENTS is a string which will be the contents
202\(instead of whatever's found in the header)." 197\(instead of whatever's found in the header\)."
203 (setq header (downcase header)) 198 (setq header (downcase header))
204 (let ((ctnts (or contents (mail-hist-current-header-contents))) 199 (let ((ctnts (or contents (mail-hist-current-header-contents)))
205 (ring (cdr (assoc header mail-hist-header-ring-alist)))) 200 (ring (cdr (assoc header mail-hist-header-ring-alist))))
206 (if (mail-hist-text-too-long-p ctnts) (setq ctnts "")) 201
202 ;; Possibly truncate the text. Note that
203 ;; `mail-hist-text-size-limit' might be nil, in which case no
204 ;; truncation would take place.
205 (setq ctnts (substring ctnts 0 mail-hist-text-size-limit))
206
207 (or ring 207 (or ring
208 ;; If the ring doesn't exist, we'll have to make it and add it 208 ;; If the ring doesn't exist, we'll have to make it and add it
209 ;; to the mail-header-ring-alist: 209 ;; to the mail-header-ring-alist:
@@ -213,6 +213,7 @@ Optional argument CONTENTS is a string which will be the contents
213 (cons (cons header ring) mail-hist-header-ring-alist)))) 213 (cons (cons header ring) mail-hist-header-ring-alist))))
214 (ring-insert ring ctnts))) 214 (ring-insert ring ctnts)))
215 215
216
216;;;###autoload 217;;;###autoload
217(defun mail-hist-put-headers-into-history () 218(defun mail-hist-put-headers-into-history ()
218 "Put headers and contents of this message into mail header history. 219 "Put headers and contents of this message into mail header history.
@@ -227,31 +228,40 @@ This function normally would be called when the message is sent."
227 (while (mail-hist-forward-header 1) 228 (while (mail-hist-forward-header 1)
228 (mail-hist-add-header-contents-to-ring 229 (mail-hist-add-header-contents-to-ring
229 (mail-hist-current-header-name))) 230 (mail-hist-current-header-name)))
231 ;; We do body contents specially. This is bad. Had I thought to
232 ;; include body-saving when I first wrote mail-hist, things might
233 ;; be cleaner now. Sigh.
230 (let ((body-contents 234 (let ((body-contents
231 (save-excursion 235 (save-excursion
232 (goto-char (point-min)) 236 (goto-char (point-min))
233 (re-search-forward 237 (re-search-forward
234 (concat "^" (regexp-quote mail-header-separator) "$") 238 (concat "^" (regexp-quote mail-header-separator)) nil)
235 nil) 239 (forward-line 1)
236 (forward-line 1) 240 (buffer-substring (point) (point-max)))))
237 (buffer-substring (point) (point-max)))))
238 (mail-hist-add-header-contents-to-ring "body" body-contents))))) 241 (mail-hist-add-header-contents-to-ring "body" body-contents)))))
239 242
240(defun mail-hist-previous-input (header) 243(defun mail-hist-header-virgin-p ()
241 "Insert the previous contents of this mail header or message body. 244 "Return non-nil if it looks like this header had no contents.
242Moves back through the history of sent mail messages. Each header has 245If it has exactly one space following the colon, then we consider it
243its own independent history, as does the body of the message. 246virgin."
247 (save-excursion
248 (mail-hist-forward-header -1)
249 (mail-hist-forward-header 1)
250 (looking-at " \n")))
244 251
245The history only contains the contents of outgoing messages, not 252(defun mail-hist-next-or-previous-input (header nextp)
246received mail." 253 "Insert next or previous contents of this mail header or message body.
247 (interactive (list (or (mail-hist-current-header-name) "body"))) 254Moves back through the history of sent mail messages. Each header has
255its own independent history, as does the body of the message."
256 (if (null header) (error "Not in a header."))
248 (setq header (downcase header)) 257 (setq header (downcase header))
249 (let* ((ring (cdr (assoc header mail-hist-header-ring-alist))) 258 (let* ((ring (cdr (assoc header mail-hist-header-ring-alist)))
250 (len (ring-length ring)) 259 (len (ring-length ring))
251 (repeat (eq last-command 'mail-hist-input-access))) 260 (repeat (eq last-command 'mail-hist-input-access)))
252 (if repeat 261 (if repeat
253 (setq mail-hist-access-count 262 (setq mail-hist-access-count
254 (ring-plus1 mail-hist-access-count len)) 263 (funcall (if nextp 'ring-minus1 'ring-plus1)
264 mail-hist-access-count len))
255 (setq mail-hist-access-count 0)) 265 (setq mail-hist-access-count 0))
256 (if (null ring) 266 (if (null ring)
257 (progn 267 (progn
@@ -259,14 +269,33 @@ received mail."
259 (message "No history for \"%s\"." header)) 269 (message "No history for \"%s\"." header))
260 (if (ring-empty-p ring) 270 (if (ring-empty-p ring)
261 (error "\"%s\" ring is empty." header) 271 (error "\"%s\" ring is empty." header)
262 (and repeat 272 (if repeat
263 (delete-region (car mail-hist-last-bounds) 273 (delete-region (car mail-hist-last-bounds)
264 (cdr mail-hist-last-bounds))) 274 (cdr mail-hist-last-bounds))
275 ;; Else if this looks like a virgin header, we'll want to
276 ;; get rid of its single space, because saved header
277 ;; contents already include that space, and it's usually
278 ;; desirable to have only one space between the colon and
279 ;; the start of your header contents.
280 (if (mail-hist-header-virgin-p)
281 (delete-backward-char 1)))
265 (let ((start (point))) 282 (let ((start (point)))
266 (insert (ring-ref ring mail-hist-access-count)) 283 (insert (ring-ref ring mail-hist-access-count))
267 (setq mail-hist-last-bounds (cons start (point))) 284 (setq mail-hist-last-bounds (cons start (point)))
268 (setq this-command 'mail-hist-input-access)))))) 285 (setq this-command 'mail-hist-input-access))))))
269 286
287
288(defun mail-hist-previous-input (header)
289 "Insert the previous contents of this mail header or message body.
290Moves back through the history of sent mail messages. Each header has
291its own independent history, as does the body of the message.
292
293The history only contains the contents of outgoing messages, not
294received mail."
295 (interactive (list (or (mail-hist-current-header-name) "body")))
296 (mail-hist-next-or-previous-input header nil))
297
298
270(defun mail-hist-next-input (header) 299(defun mail-hist-next-input (header)
271 "Insert next contents of this mail header or message body. 300 "Insert next contents of this mail header or message body.
272Moves back through the history of sent mail messages. Each header has 301Moves back through the history of sent mail messages. Each header has
@@ -279,27 +308,8 @@ without having called `mail-hist-previous-header' first
279The history only contains the contents of outgoing messages, not 308The history only contains the contents of outgoing messages, not
280received mail." 309received mail."
281 (interactive (list (or (mail-hist-current-header-name) "body"))) 310 (interactive (list (or (mail-hist-current-header-name) "body")))
282 (setq header (downcase header)) 311 (mail-hist-next-or-previous-input header t))
283 (let* ((ring (cdr (assoc header mail-hist-header-ring-alist))) 312
284 (len (ring-length ring))
285 (repeat (eq last-command 'mail-hist-input-access)))
286 (if repeat
287 (setq mail-hist-access-count
288 (ring-minus1 mail-hist-access-count len))
289 (setq mail-hist-access-count 0))
290 (if (null ring)
291 (progn
292 (ding)
293 (message "No history for \"%s\"." header))
294 (if (ring-empty-p ring)
295 (error "\"%s\" ring is empty." header)
296 (and repeat
297 (delete-region (car mail-hist-last-bounds)
298 (cdr mail-hist-last-bounds)))
299 (let ((start (point)))
300 (insert (ring-ref ring mail-hist-access-count))
301 (setq mail-hist-last-bounds (cons start (point)))
302 (setq this-command 'mail-hist-input-access))))))
303 313
304(provide 'mail-hist) 314(provide 'mail-hist)
305 315