]> code.delx.au - gnu-emacs/blobdiff - lisp/mail/mailabbrev.el
merge conflict
[gnu-emacs] / lisp / mail / mailabbrev.el
index c99b2a22d3de5632d055ad2122ef9c18f3f940e3..c1a6c39ad634326c2941744840cff5c5806ea46a 100644 (file)
@@ -1,9 +1,10 @@
 ;;; mailabbrev.el --- abbrev-expansion of mail aliases
 
 ;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1996, 1997, 2000, 2001,
-;;   2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;;   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;;   Free Software Foundation, Inc.
 
-;; Author: Jamie Zawinski <jwz@lucid.com>, now <jwz@jwz.org>
+;; Author: Jamie Zawinski <jwz@lucid.com; now jwz@jwz.org>
 ;; Maintainer: FSF
 ;; Created: 19 Oct 90
 ;; Keywords: mail
@@ -261,7 +262,12 @@ also want something like \",\\n    \" to get each address on its own line.")
 ;;;###autoload
 (defun define-mail-abbrev (name definition &optional from-mailrc-file)
   "Define NAME as a mail alias abbrev that translates to DEFINITION.
-If DEFINITION contains multiple addresses, separate them with commas."
+If DEFINITION contains multiple addresses, separate them with commas.
+
+Optional argument FROM-MAILRC-FILE means that DEFINITION comes
+from a mailrc file.  In that case, addresses are separated with
+spaces and addresses with embedded spaces are surrounded by
+double-quotes."
   ;; When this is called from build-mail-abbrevs, the third argument is
   ;; true, and we do some evil space->comma hacking like /bin/mail does.
   (interactive "sDefine mail alias: \nsDefine %s as mail alias for: ")
@@ -272,33 +278,62 @@ If DEFINITION contains multiple addresses, separate them with commas."
       (setq definition (substring definition (match-end 0))))
   (if (string-match "[ \t\n,]+\\'" definition)
       (setq definition (substring definition 0 (match-beginning 0))))
-  (let* ((result '())
-        (L (length definition))
+  (let* ((L (length definition))
         (start (if (> L 0) 0))
-        end)
+        end this-entry result)
     (while start
-      ;; If we're reading from the mailrc file, then addresses are delimited
-      ;; by spaces, and addresses with embedded spaces must be surrounded by
-      ;; double-quotes.  Otherwise, addresses are separated by commas.
-      (if from-mailrc-file
-         (if (eq ?\" (aref definition start))
-             (setq start (1+ start)
-                   end (string-match "\"[ \t,]*" definition start))
-           (setq end (string-match "[ \t,]+" definition start)))
-       (setq end (string-match "[ \t\n,]*,[ \t\n,]*" definition start)))
-      (let ((tem (substring definition start end)))
+      (cond
+       (from-mailrc-file
+       ;; If we're reading from the mailrc file, addresses are
+       ;; delimited by spaces, and addresses with embedded spaces are
+       ;; surrounded by non-escaped double-quotes.
+       (if (eq ?\" (aref definition start))
+           (setq start (1+ start)
+                 end (and (string-match
+                           "[^\\]\\(\\([\\][\\]\\)*\\)\"[ \t,]*"
+                           definition start)
+                          (match-end 1)))
+         (setq end (string-match "[ \t,]+" definition start)))
+       ;; Extract the address and advance the loop past it.
+       (setq this-entry (substring definition start end)
+             start (and end (/= (match-end 0) L) (match-end 0)))
+       ;; If the full name contains a problem character, quote it.
+       (and (string-match "\\(.+?\\)[ \t]*\\(<.*>\\)" this-entry)
+            (string-match "[^- !#$%&'*+/0-9=?A-Za-z^_`{|}~]"
+                          (match-string 1 this-entry))
+            (setq this-entry (replace-regexp-in-string
+                              "\\(.+?\\)[ \t]*\\(<.*>\\)"
+                              "\"\\1\" \\2"
+                              this-entry)))
+       (push this-entry result))
+       ;; When we are not reading from .mailrc, addresses are
+       ;; separated by commas.  Try to accept a rfc822-like syntax.
+       ;; (Todo: extend rfc822.el to do the work for us.)
+       ((equal (string-match
+               "[ \t,]*\\(\"\\(?:[^\"]\\|[^\\]\\(?:[\\][\\]\\)*\"\\)*\"[ \t]*\
+<[-.!#$%&'*+/0-9=?A-Za-z^_`{|}~@]+>\\)[ \t,]*"
+               definition start)
+              start)
+       ;; If an entry has a valid [ "foo bar" <foo@example.com> ]
+       ;; form, use it literally .  This also allows commas in the
+       ;; quoted string, e.g.  [ "foo bar, jr" <foo@example.com> ]
+       (push (match-string 1 definition) result)
+       (setq start (and (/= (match-end 0) L) (match-end 0))))
+       (t
+       ;; Otherwise, read the next address by looking for a comma.
+       (setq end (string-match "[ \t\n,]*,[ \t\n]*" definition start))
+       (setq this-entry (substring definition start end))
        ;; Advance the loop past this address.
-       (setq start (and end
-                        (/= (match-end 0) L)
-                        (match-end 0)))
+       (setq start (and end (/= (match-end 0) L) (match-end 0)))
        ;; If the full name contains a problem character, quote it.
-       (when (string-match "\\(.+?\\)[ \t]*\\(<.*>\\)" tem)
-         (if (string-match "[^- !#$%&'*+/0-9=?A-Za-z^_`{|}~]"
-                           (match-string 1 tem))
-             (setq tem (replace-regexp-in-string
-                        "\\(.+?\\)[ \t]*\\(<.*>\\)" "\"\\1\" \\2"
-                        tem))))
-       (push tem result)))
+       (and (string-match "\\(.+?\\)[ \t]*\\(<.*>\\)" this-entry)
+            (string-match "[^- !#$%&'*+/0-9=?A-Za-z^_`{|}~]"
+                          (match-string 1 this-entry))
+            (setq this-entry (replace-regexp-in-string
+                              "\\(.+?\\)[ \t]*\\(<.*>\\)" "\"\\1\" \\2"
+                              this-entry)))
+       (push this-entry result))))
+
     (setq definition (mapconcat (function identity)
                                (nreverse result)
                                mail-alias-separator-string)))
@@ -466,12 +501,12 @@ of a mail alias.  The value is set up, buffer-local, when first needed.")
             ;; when the user types -.)  Check the character's syntax in
             ;; the usual syntax table.
 
-            (or (and (integerp last-command-char)
+            (or (and (integerp last-command-event)
                      ;; Some commands such as M-> may want to expand first.
                      (equal this-command 'self-insert-command)
-                     (or (eq (char-syntax last-command-char) ?_)
+                     (or (eq (char-syntax last-command-event) ?_)
                          ;; Don't expand on @.
-                         (memq last-command-char '(?@ ?. ?% ?! ?_ ?-))))
+                         (memq last-command-event '(?@ ?. ?% ?! ?_ ?-))))
                 ;; Use this table so that abbrevs can have hyphens in them.
                 (with-syntax-table mail-abbrev-syntax-table
                   (funcall expand))))
@@ -534,62 +569,34 @@ of a mail alias.  The value is set up, buffer-local, when first needed.")
   ;; Based on lisp.el:lisp-complete-symbol
   (interactive)
   (mail-abbrev-make-syntax-table)
-  (let* ((end (point))
-        (beg (with-syntax-table mail-abbrev-syntax-table
-                (save-excursion
-                  (backward-word 1)
-                  (point))))
-         (alias (buffer-substring beg end))
-        (completion (try-completion alias mail-abbrevs)))
-    (cond ((eq completion t)
-          (message "%s" alias))        ; confirm
-         ((null completion)
-          (error "[Can't complete \"%s\"]" alias)) ; (message ...) (ding)
-         ((not (string= completion alias))
-          (delete-region beg end)
-          (insert completion))
-         (t (with-output-to-temp-buffer "*Completions*"
-              (display-completion-list
-               (prog2
-                   (message "Making completion list...")
-                   (all-completions alias mail-abbrevs)
-                 (message "Making completion list...done"))
-               alias))))))
+  (let ((end (point))
+        (beg (with-syntax-table mail-abbrev-syntax-table
+               (save-excursion
+                 (backward-word 1)
+                 (point)))))
+    (completion-in-region beg end mail-abbrevs)))
 
 (defun mail-abbrev-next-line (&optional arg)
-  "Expand any mail abbrev, then move cursor vertically down ARG lines.
-If there is no character in the target line exactly under the current column,
-the cursor is positioned after the character in that line which spans this
-column, or at the end of the line if it is not long enough.
-If there is no line in the buffer after this one,
-a newline character is inserted to create a line
-and the cursor moves to that line.
-
-The command \\[set-goal-column] can be used to create
-a semipermanent goal column to which this command always moves.
-Then it does not try to move vertically.  This goal column is stored
-in `goal-column', which is nil when there is none.
-
-If you are thinking of using this in a Lisp program, consider
-using `forward-line' instead.  It is usually easier to use
-and more reliable (no dependence on goal column, etc.)."
+  "Expand a mail abbrev before point, then move vertically down ARG lines.
+This only expands an abbrev (if one is present) if called with
+point at the end of a line, or on whitespace before the end of a line.
+
+In terms of line motion, this behaves like `next-line', which see."
   (interactive "p")
   (if (looking-at "[ \t]*\n") (expand-abbrev))
   (setq this-command 'next-line)
   (with-no-warnings (next-line arg)))
 
 (defun mail-abbrev-end-of-buffer (&optional arg)
-  "Expand any mail abbrev, then move point to end of buffer.
-Leave mark at previous position.
-With arg N, put point N/10 of the way from the true end.
+  "Expand a mail abbrev before point, then move to the end of the buffer.
+This only expands an abbrev (if one is present) if called with
+point at the end of a line, or on whitespace before the end of a line.
 
-Don't use this command in Lisp programs!
-\(goto-char (point-max)) is faster and avoids clobbering the mark."
+In other respects, this behaves like `end-of-buffer', which see."
   (interactive "P")
   (if (looking-at "[ \t]*\n") (expand-abbrev))
   (setq this-command 'end-of-buffer)
-  (with-no-warnings
-   (end-of-buffer arg)))
+  (with-no-warnings (end-of-buffer arg)))
 
 (eval-after-load "sendmail"
   '(progn