rbj@dsys.icst.nbs.GOV (Root Boy Jim) (05/03/89)
? From: Bob Weiner <gatech!uflorida!novavax!weiner@bbn.com>
? I recently posted revisions to buff-menu.el, rmail.el, rmailsum.el,
? info.el, and informat.el. All of these are based on GNU Emacs 18.52 and
? can probably easily be integrated with any 18.53 updates.
They probably could. However, I have a slight disagreement with your
posting methods. Trivial modifications should probably be posted as
hooks, leaving the distributed code alone. More extensive mods should
possibly be posted as diffs. My own method is demonstrated
below, this seeming to be a good place to post rbj-mail. When I need to
redefine a major function, I do so in the autoloaded elisp file. I
solicit opinions on people's preferred methods.
? Bob Weiner, Motorola, Inc., USENET: ...!gatech!uflorida!novavax!weiner
? (407) 738-2087
The following is a description of my rmail enhancements:
mail-mode:
yowza replaces region with Zippy quote
mail-quote use when responding from mail with ~e
deletes header, quotes body, inserts
~/.signature, inserts Zippy quote
mail-yank-original quote with "? " instead of indenting
rmail-mode:
rmail-mode-map / -> rmail-search
H -> rmail-header-clean
I -> rmail-set-inbox-list
U -> undigestify-rmail-message
rmail-header-clean Removes worthless headers.
Can reduce some rmail files by 25%!
rmail-summary-mode-map ^J -> rmail-summary-goto-msg (j)
O, A, K like o, a, k in rmail-mode.
C-P, C-N normal motion
M-p, M-n do what C-p, C-n did
P, N do what M-p, M-n did
S -> rmail-summary-sort
% -> rmail-summary-split
rmail-output-other-window O == C-x o, o, C-x o
rmail-add-label-other-window A == C-x o, a, C-x o
rmail-kill-label-other-window K == C-x o, k, C-x o
rmail-summary-sort CHECK IT OUT! sorts the rmail-summary
buffer by subject. Breeze thru topics!
rmail-summary-split Another nifty one. Splits a buffer by
prefix-argument'th letter of subject.
When an rmail file gets too big,
split it up into little files. File
"foo" is split into "foo-a" thru "foo-z".
rmail-summary-column Constant. Column subject starts in summary.
rmail-summary-goto-msg Redefinition. Fixes a bug when summary
buffer is sorted. If msg 17 precedes
msg 1, old version would goto msg 17 in
the summary buffer. Added the regexp
"[^0-9]" to the end of concat.
rmail-summary-reuse Variable. Its intent is to force
rmail-summary to recalculate summary lines.
rmail-summary Redefinition. Force summary line to be
recalculated if invoked with an arg. Upon
retrospect, the setq should probably be a
let. Should probably not be a global
variable either. Hack, hack.
rmail-make-summary-line Redefinition. Uses rmail-summary-reuse.
rmail-make-summary-line-1 Redefinition. PUTS MESSAGE SIZE IN SUMMARY
buffer but not in rmail file. Neat for
finding duplicate messages.
Perhaps I should have made a shar file or diffs, and modified the
describe-mode documentation. However, my point was to demonstrate
modification with hooks and autoloading, and not modify GNU code.
My apologys if this is slightly wrong, as it is an extract. You really
don't want to see my entire elisp library, now do you? :-)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.emacs: (partial)
(global-set-key "\^x^y" 'yowza)
(autoload 'yowza "mail-hook" "Region to Zippy quote" t) ; ^X^Y
(autoload 'mail-mode-hook "mail-hook" "Mail Mode Hook")
(autoload 'rmail-mode-hook "mail-hook" "Rmail Mode Hook")
(autoload
'rmail-summary-mode-hook "mail-hook" "Rmail Summary Mode Hook")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mail-hook.el:
(require 'sendmail) ; I redefine mail-yank-original
(require 'rmail) ; Do I need this? (probably)
(load "rmailsum") ; rmailsum.el has no provide
;;;; MAIL MODE
(defun mail-mode-hook ()
"Redefine Quoting in Reply Mail"
(define-key mail-mode-map "\e\"" 'mail-quote)
(setq mail-mode-hook nil))
;;; From /gnu/lisp/sendmail.el
(defun mail-yank-original (arg)
"Insert the message being replied to, if any (in rmail).
Puts point before the text and mark after.
Indents each nonblank line ARG spaces (default 3).
*** RBJ indents with the string '? ' always ***.
Just \\[universal-argument] as argument means don't indent
and don't delete any header fields."
(interactive "P")
(if mail-reply-buffer
(let ((start (point)))
(delete-windows-on mail-reply-buffer)
(insert-buffer mail-reply-buffer)
(if (consp arg)
nil
(mail-yank-clear-headers start (mark))
(save-excursion
(save-restriction
(narrow-to-region start (mark))
(goto-char (point-min))
(replace-regexp "^." "? \\&"))) ; RBJ
)
(exchange-point-and-mark)
(if (not (eolp)) (insert ?\n)))))
;;; Mail Utility Functions
(defun yowza (beg end) ; ^X^Y
"Replace region with YOW quote."
(interactive "*r")
(call-process-region beg end "yow" t t t))
(defun mail-quote () ; \e""
"Rip off Mail Header and Quote Body"
(interactive "*")
(beginning-of-buffer)
(re-search-forward "^ *$")
(forward-char)
(delete-region (point-min) (point))
(while (not (eobp))
(if (looking-at ".")
(insert "? "))
(forward-line))
(insert-file "~/.signature")
(end-of-buffer)
(push-mark)
(yowza (point) (point)))
;;; RMAIL MODE functions
(defun rmail-mode-hook ()
"Rmail Mode Hook"
(define-key rmail-mode-map "/" 'rmail-search)
(define-key rmail-mode-map "H" 'rmail-header-clean)
(define-key rmail-mode-map "I" 'set-rmail-inbox-list)
(define-key rmail-mode-map "U" 'undigestify-rmail-message)
(setq rmail-mode-hook nil))
;;; Rmail header cleaning
(defun rmail-header-clean-internal (l) "Clean gubbish from rmail headers."
(mapcar (function (lambda (r)
(setq size (point-max))
(message "%d/%d (%d%%); `%s'"
size max (/ size (/ max 100)) r)
(goto-char 1)
(delete-matching-lines r)))
l))
(defun rmail-header-clean () "Clean gubbish from rmail headers."
(interactive)
(widen)
(let ((buffer-read-only nil) (case-fold-search t)
(size 0) (max (point-max)))
(rmail-header-clean-internal
(list "^Received: " "^Message-I[dD]: " "^References: "
"^In-Reply-To: " "^\tid <?A[AB][0-9]+[@a-z0-9.>-]*;"
"^Approved: " "^Newsgroups: " "^Keywords: "
"^\t(?contact .* if you have questions[).]*$"
"^Followup-To: " "^Mmdf-Warning: "
"^\\(Nf-\\|Resent-\\)[a-z-]+: "
(concat "^\tfor \\("
"arpa-unix-emacs@bbn\\.com (" "\\|"
"[a-z+-]+@prep\\.ai\\.mit\\.edu (" "\\|"
"gnu-manual@a\\.cs\\.uiuc\\.edu (" "\\|"
"namedroppers@sri-nic\\.arpa (" "\\|"
"tcp-ip@sri-nic\\.arpa (" "\\|"
"xpert@[a-z.]+\\.mit\\.edu (" "\\)")
(concat "^Reply-To: \\("
"INFO-UNIX@brl\\.mil" "\\|"
"UNIX-WIZARDS@brl\\.mil" "\\|"
"Sun-Spots@rice\\.edu" "\\|"
"std-unix@uunet\\.uu\\.net" "\\|"
"tcp-ip@sri-nic\\.arpa" "\\)$")
(concat "Return-Path: \\("
"<[a-z+-]+-request@prep\\.ai\\.mit\\.edu>" "\\|"
"<arpa-unix-emacs-request@[a-z]+\\.bbn\\.com>" "\\|"
"<info-mach-Request@wb1\\.cs\\.cmu\\.edu>" "\\|"
"<namedroppers-RELAY@sri-nic\\.arpa>" "\\|"
"<info-unix-request@sem\\.brl\\.mil>" "\\|"
"<unix-wizards-request@sem\\.brl\\.mil>" "\\|"
"<unix-sources-request@smoke\\.brl\\.mil>" "\\|"
"<tcp-ip-RELAY@sri-nic\\.arpa>" "\\|"
"<Sun-Spots-Request@rice\\.edu>" "\\|"
"<xpert-request@[a-z.]+\\.mit\\.edu>" "\\)$")
(concat "^Sender: \\("
"arpa-unix-emacs-request@bbn\\.com" "\\|"
"[a-z+-]+-request@prep\\.ai\\.mit\\.edu" "\\|"
"unix-emacs-request@BBN\\.COM" "\\|"
"namedroppers-request@sri-nic\\.arpa" "\\|"
"tcp-ip-request@sri-nic\\.arpa" "\\|"
"xpert-request@[a-z.]+\\.mit\\.edu" "\\)$")
(concat "^\\(Cc\\|To\\): \\("
"tcp-ip@sri-nic\\.arpa" "\\|"
"xpert@[a-z.]+\\.mit\\.edu" "\\)$")
"^Source-Info: " "^Status: "
))
(setq size (point-max))
(message "Done, %d -> %d, %d (%d%%)"
max size (- size max) (/ size (/ max 100))))
(rmail-show-message 1))
;;; RMAIL SUMMARY MODE
(defun rmail-summary-mode-hook ()
"Rmail Summary Mode Hook"
(define-key rmail-summary-mode-map "\^n" nil)
(define-key rmail-summary-mode-map "\^p" nil)
(define-key rmail-summary-mode-map "\en" 'rmail-summary-next-all)
(define-key rmail-summary-mode-map "N" 'rmail-summary-next-all)
(define-key rmail-summary-mode-map "\ep" 'rmail-summary-previous-all)
(define-key rmail-summary-mode-map "P" 'rmail-summary-previous-all)
(define-key rmail-summary-mode-map "\^j" 'rmail-summary-goto-msg)
(define-key rmail-summary-mode-map "O" 'rmail-output-other-window)
(define-key rmail-summary-mode-map "A" 'rmail-add-label-other-window)
(define-key rmail-summary-mode-map "K" 'rmail-kill-label-other-window)
(define-key rmail-summary-mode-map "S" 'rmail-summary-sort)
(define-key rmail-summary-mode-map "%" 'rmail-summary-split)
(setq rmail-summary-mode-hook nil))
;;; Rmail {output,add/kill label} (to rmail file) other window
(defun rmail-output-other-window ()
"Like C-x o, o, C-x o."
(interactive)
(other-window 1)
(call-interactively 'rmail-output-to-rmail-file)
(other-window 1))
(defun rmail-add-label-other-window ()
"Like C-x o, a, C-x o."
(interactive)
(other-window 1)
(call-interactively 'rmail-add-label)
(other-window 1))
(defun rmail-kill-label-other-window ()
"Like C-x o, k, C-x o."
(interactive)
(other-window 1)
(call-interactively 'rmail-kill-label)
(other-window 1))
(defconst rmail-summary-column 50
"Column `Subject' field starts in summary buffer.
Note that this is eight more than it used to be
because of addition of message size to summary.")
;;; Rmail summary sort
(defun rmail-summary-sort ()
"Sort the Rmail Summary buffer."
(interactive)
(let ((buffer-read-only nil))
(mark-whole-buffer)
(downcase-region 1 (point-max))
(replace-regexp "re:[ ]+" "" nil)
(goto-char (point-max))
(while (> (+ 4 rmail-summary-column) (current-column)) ; len(subj) > 4
(end-of-line 0))
(sort-columns nil rmail-summary-column (point))))
;;; Rmail summary split
(defun rmail-summary-split (col)
"Sort the Rmail Summary buffer."
(interactive "p")
(let ((buffer-read-only nil)
(sfx)
(file)
)
(mark-whole-buffer)
(downcase-region 1 (point-max))
(replace-regexp "re:[ ]+" "" nil)
(goto-char 1)
(while (not (eobp))
(move-to-column (+ rmail-summary-column col -1))
(setq sfx (char-after (point)))
(sit-for 0)
(or (and (<= ?A sfx) (<= sfx ?Z))
(and (<= ?a sfx) (<= sfx ?z))
(setq sfx ?@))
(save-excursion
(rmail-summary-goto-msg)
(other-window 1)
(setq file (concat (buffer-name) "-"
(char-to-string sfx)))
(rmail-output-to-rmail-file file)
(other-window 1)
(rmail-summary-delete-forward))
(beginning-of-line 2))))
;;;; REDEFINITIONS from rmailsum.el
;;;; Fix bug when summary buffer has been resorted
(defun rmail-summary-goto-msg (&optional n nowarn)
(interactive "P")
(if (consp n) (setq n (prefix-numeric-value n)))
(if (eobp) (forward-line -1))
(beginning-of-line)
(let ((buf rmail-buffer)
(cur (point))
(curmsg (string-to-int
(buffer-substring (point)
(min (point-max) (+ 5 (point)))))))
(if (not n)
(setq n curmsg)
(if (< n 1)
(progn (message "No preceding message")
(setq n 1)))
(if (> n rmail-total-messages)
(progn (message "No following message")
(goto-char (point-max))
(rmail-summary-goto-msg)))
(goto-char (point-min))
(if (not (re-search-forward (concat "^ *" (int-to-string n)
"[^0-9]") nil t))
(progn (or nowarn (message "Message %d not found" n))
(setq n curmsg)
(goto-char cur))))
(beginning-of-line)
(skip-chars-forward " ")
(skip-chars-forward "0-9")
(save-excursion (if (= (following-char) ?-)
(let ((buffer-read-only nil))
(delete-char 1)
(insert " "))))
(beginning-of-line)
(pop-to-buffer buf)
(rmail-show-message n)
(pop-to-buffer rmail-summary-buffer)))
;; Redefine RMAIL-SUMMARY to always recompute if given ARG
(defvar rmail-summary-reuse t) ;RBJ
(defun rmail-summary (arg)
"Display a summary of all messages, one line per message."
(interactive "P")
(setq rmail-summary-reuse (not arg)) ;RBJ
(rmail-new-summary "All" nil))
(defun rmail-make-summary-line (msg)
(let ((line (or (and rmail-summary-reuse ;RBJ
(aref rmail-summary-vector (1- msg)))
(progn
(setq new-summary-line-count
(1+ new-summary-line-count))
(if (zerop (% new-summary-line-count 10))
(message "Computing summary lines...%d"
new-summary-line-count))
(rmail-make-summary-line-1 msg)))))
;; Fix up the part of the summary that says "deleted" or "unseen".
(aset line 4
(if (rmail-message-deleted-p msg) ?\D
(if (= ?0 (char-after (+ 3 (rmail-msgbeg msg))))
?\- ?\ )))
line))
(defun rmail-make-summary-line-1 (msg)
(goto-char (rmail-msgbeg msg))
(let* ((lim (save-excursion (forward-line 2) (point)))
pos
(labels
(progn
(forward-char 3)
(concat
; (if (save-excursion (re-search-forward ",answered," lim t))
; "*" "")
; (if (save-excursion (re-search-forward ",filed," lim t))
; "!" "")
(if (progn (search-forward ",,") (eolp))
""
(concat "{"
(buffer-substring (point)
(progn (end-of-line) (point)))
"} ")))))
(line
(progn
(forward-line 1)
(if (looking-at "Summary-line: ")
(progn
(goto-char (match-end 0))
(setq line
(buffer-substring (point)
(progn (forward-line 1) (point)))))))))
;; Obsolete status lines lacking a # should be flushed.
(and line
(not (string-match "#" line))
(progn
(delete-region (point)
(progn (forward-line -1) (point)))
(setq line nil)))
;; If we didn't get a valid status line from the message,
;; make a new one and put it in the message.
(or line
(let* ((case-fold-search t)
(next (rmail-msgend msg))
(beg (if (progn (goto-char (rmail-msgbeg msg))
(search-forward "\n*** EOOH ***\n" next t))
(point)
(forward-line 1)
(point)))
(end (progn (search-forward "\n\n" nil t) (point))))
(save-restriction
(narrow-to-region beg end)
(goto-char beg)
(setq line (rmail-make-basic-summary-line)))
(goto-char (rmail-msgbeg msg))
(forward-line 2)
(insert "Summary-line: " line)))
(setq pos (string-match "#" line))
(aset rmail-summary-vector (1- msg)
(concat (format "%4d%8d " msg
(- (rmail-msgend msg) ;RBJ
(rmail-msgbeg msg))) ;RBJ
(substring line 0 pos)
labels
(substring line (1+ pos))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Root Boy Jim is what I am
Are you what you are or what?weiner%novavax@uflorida.UUCP (Bob Weiner) (05/04/89)
Date: Tue, 2 May 89 20:16:00 EDT From: Root Boy Jim <uflorida!gatech!mailrus!dsys.icst.nbs.gov!rbj> Organization: National Institute of Standards and Technology formerly National Bureau of Standards Disclaimer: Opinions expressed are those of the sender and do not reflect NIST policy or agreement. ? From: Bob Weiner <gatech!uflorida!novavax!weiner@bbn.com> ? I recently posted revisions to buff-menu.el, rmail.el, rmailsum.el, ? info.el, and informat.el. All of these are based on GNU Emacs 18.52 and ? can probably easily be integrated with any 18.53 updates. They probably could. However, I have a slight disagreement with your posting methods. Trivial modifications should probably be posted as hooks, leaving the distributed code alone. More extensive mods should possibly be posted as diffs. My own method is demonstrated below, this seeming to be a good place to post rbj-mail. When I need to redefine a major function, I do so in the autoloaded elisp file. I solicit opinions on people's preferred methods. Dear RBJ (great name and I do like beautiful Edie Brickell), I did think about posting diffs for my mods, but I decided that many people like myself decide rapidly whether to pick up code form the net. The easier the install, the better. This way they can take the file, do a quick diff with their own, to see if they have any extra functionality and then just use the code as is or add in a few extra functions. Your hook ideas do give some benefit but they also complicate the install greatly. Additionally, I made the mods for myself, not to distribute, but in the end, I felt they would benefit many people as is. Work constraints and all prevents me from working as dilligently on this sort of thing as FSF people do. I appreciate the comments and the code, though. Your sorting features looked like good ideas. I am, Bob