diff options
| author | Karl Fogel | 1996-05-08 02:38:37 +0000 |
|---|---|---|
| committer | Karl Fogel | 1996-05-08 02:38:37 +0000 |
| commit | 1747a1941c1229b41e22ba249ca365dc0ec99d1b (patch) | |
| tree | 4430c9824c100ddb21e467388c2ceb562777bd51 | |
| parent | a15269c0d04259277ff1d9d6a6dac8b60184ece3 (diff) | |
| download | emacs-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.el | 206 |
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.") | |||
| 100 | Returns nil if not in a header, implying that point is in the body of | 102 | Returns nil if not in a header, implying that point is in the body of |
| 101 | the message." | 103 | the 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). |
| 124 | If last/first header is encountered first, stop there and returns | 124 | If last/first header is encountered first, stop there and returns |
| 125 | nil. | 125 | nil. |
| 126 | 126 | Places point directly after the colon." | |
| 127 | Places point on the first non-whitespace on the line following the | 127 | (let ((boundary |
| 128 | colon after the header name, or on the second space following that if | 128 | (save-excursion |
| 129 | the 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 |
| 191 | If the value is nil, that means no limit on text size.") | 190 | characters, 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. | ||
| 195 | The 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. |
| 195 | HEADER is a string; it will be downcased. | ||
| 201 | Optional argument CONTENTS is a string which will be the contents | 196 | Optional 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. |
| 242 | Moves back through the history of sent mail messages. Each header has | 245 | If it has exactly one space following the colon, then we consider it |
| 243 | its own independent history, as does the body of the message. | 246 | virgin." |
| 247 | (save-excursion | ||
| 248 | (mail-hist-forward-header -1) | ||
| 249 | (mail-hist-forward-header 1) | ||
| 250 | (looking-at " \n"))) | ||
| 244 | 251 | ||
| 245 | The history only contains the contents of outgoing messages, not | 252 | (defun mail-hist-next-or-previous-input (header nextp) |
| 246 | received mail." | 253 | "Insert next or previous contents of this mail header or message body. |
| 247 | (interactive (list (or (mail-hist-current-header-name) "body"))) | 254 | Moves back through the history of sent mail messages. Each header has |
| 255 | its 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. | ||
| 290 | Moves back through the history of sent mail messages. Each header has | ||
| 291 | its own independent history, as does the body of the message. | ||
| 292 | |||
| 293 | The history only contains the contents of outgoing messages, not | ||
| 294 | received 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. |
| 272 | Moves back through the history of sent mail messages. Each header has | 301 | Moves back through the history of sent mail messages. Each header has |
| @@ -279,27 +308,8 @@ without having called `mail-hist-previous-header' first | |||
| 279 | The history only contains the contents of outgoing messages, not | 308 | The history only contains the contents of outgoing messages, not |
| 280 | received mail." | 309 | received 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 | ||