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