Revision: miles@gnu.org--gnu-2005/gnus--devo--0--patch-151
[gnus] / lisp / gnus-art.el
index 3c1488e..5c3c0bb 100644 (file)
@@ -19,8 +19,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -373,7 +373,13 @@ advertisements.  For example:
                      (or (nth 4 spec) 3)
                      (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
              types))
-     '(("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
+     '(;; I've never seen anyone use this strikethru convention whereas I've
+       ;; several times seen it triggered by normal text.  --Stef
+       ;; Miles suggests that this form is sometimes used but for italics,
+       ;; so maybe we should map it to `italic'.
+       ;; ("\\(\\s-\\|^\\)\\(-\\(\\(\\w\\|-[^-]\\)+\\)-\\)\\(\\s-\\|[?!.,;]\\)"
+       ;; 2 3 gnus-emphasis-strikethru)
+       ("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
        2 3 gnus-emphasis-underline))))
   "*Alist that says how to fontify certain phrases.
 Each item looks like this:
@@ -485,9 +491,6 @@ be fed to `format-time-string'."
   :link '(custom-manual "(gnus)Article Date")
   :group 'gnus-article-washing)
 
-(eval-and-compile
-  (autoload 'mail-extract-address-components "mail-extr"))
-
 (defcustom gnus-save-all-headers t
   "*If non-nil, don't remove any headers before saving."
   :group 'gnus-article-saving
@@ -657,21 +660,23 @@ above them."
   :type 'face
   :group 'gnus-article-buttons)
 
-(defcustom gnus-signature-face 'gnus-signature-face
+(defcustom gnus-signature-face 'gnus-signature
   "Face used for highlighting a signature in the article buffer.
-Obsolete; use the face `gnus-signature-face' for customizations instead."
+Obsolete; use the face `gnus-signature' for customizations instead."
   :type 'face
   :group 'gnus-article-highlight
   :group 'gnus-article-signature)
 
-(defface gnus-signature-face
+(defface gnus-signature
   '((t
      (:italic t)))
   "Face used for highlighting a signature in the article buffer."
   :group 'gnus-article-highlight
   :group 'gnus-article-signature)
+;; backward-compatibility alias
+(put 'gnus-signature-face 'face-alias 'gnus-signature)
 
-(defface gnus-header-from-face
+(defface gnus-header-from
   '((((class color)
       (background dark))
      (:foreground "spring green"))
@@ -683,8 +688,10 @@ Obsolete; use the face `gnus-signature-face' for customizations instead."
   "Face used for displaying from headers."
   :group 'gnus-article-headers
   :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-from-face 'face-alias 'gnus-header-from)
 
-(defface gnus-header-subject-face
+(defface gnus-header-subject
   '((((class color)
       (background dark))
      (:foreground "SeaGreen3"))
@@ -696,8 +703,10 @@ Obsolete; use the face `gnus-signature-face' for customizations instead."
   "Face used for displaying subject headers."
   :group 'gnus-article-headers
   :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-subject-face 'face-alias 'gnus-header-subject)
 
-(defface gnus-header-newsgroups-face
+(defface gnus-header-newsgroups
   '((((class color)
       (background dark))
      (:foreground "yellow" :italic t))
@@ -711,8 +720,10 @@ In the default setup this face is only used for crossposted
 articles."
   :group 'gnus-article-headers
   :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-newsgroups-face 'face-alias 'gnus-header-newsgroups)
 
-(defface gnus-header-name-face
+(defface gnus-header-name
   '((((class color)
       (background dark))
      (:foreground "SeaGreen"))
@@ -724,8 +735,10 @@ articles."
   "Face used for displaying header names."
   :group 'gnus-article-headers
   :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-name-face 'face-alias 'gnus-header-name)
 
-(defface gnus-header-content-face
+(defface gnus-header-content
   '((((class color)
       (background dark))
      (:foreground "forest green" :italic t))
@@ -736,12 +749,14 @@ articles."
      (:italic t)))  "Face used for displaying header content."
   :group 'gnus-article-headers
   :group 'gnus-article-highlight)
+;; backward-compatibility alias
+(put 'gnus-header-content-face 'face-alias 'gnus-header-content)
 
 (defcustom gnus-header-face-alist
-  '(("From" nil gnus-header-from-face)
-    ("Subject" nil gnus-header-subject-face)
-    ("Newsgroups:.*," nil gnus-header-newsgroups-face)
-    ("" gnus-header-name-face gnus-header-content-face))
+  '(("From" nil gnus-header-from)
+    ("Subject" nil gnus-header-subject)
+    ("Newsgroups:.*," nil gnus-header-newsgroups)
+    ("" gnus-header-name gnus-header-content))
   "*Controls highlighting of article headers.
 
 An alist of the form (HEADER NAME CONTENT).
@@ -2147,33 +2162,33 @@ unfolded."
       ;; read-only.
       (if (and wash-face-p (memq 'face gnus-article-wash-types))
          (gnus-delete-images 'face)
-       (let (face faces)
-         (save-excursion
+       (let (face faces from)
+         (save-current-buffer
            (when (and wash-face-p
-                      (progn
-                        (goto-char (point-min))
-                        (not (re-search-forward "^Face:[\t ]*" nil t)))
-                      (gnus-buffer-live-p gnus-original-article-buffer))
+                      (gnus-buffer-live-p gnus-original-article-buffer)
+                      (not (re-search-forward "^Face:[\t ]*" nil t)))
              (set-buffer gnus-original-article-buffer))
            (save-restriction
              (mail-narrow-to-head)
              (while (gnus-article-goto-header "Face")
-               (setq faces (nconc faces (list (mail-header-field-value)))))))
-         (dolist (face faces)
-           (let ((png (gnus-convert-face-to-png face))
-                 image)
-             (when png
-               (setq image
-                     (apply 'gnus-create-image png 'png t
-                            (cdr (assq 'png gnus-face-properties-alist))))
-               (gnus-article-goto-header "from")
-               (when (bobp)
-                 (insert "From: [no `from' set]\n")
-                 (forward-char -17))
-               (gnus-add-wash-type 'face)
-               (gnus-add-image 'face image)
-               (gnus-put-image image nil 'face))))))
-      )))
+               (push (mail-header-field-value) faces))))
+         (when faces
+           (goto-char (point-min))
+           (let ((from (gnus-article-goto-header "from"))
+                 png image)
+             (unless from
+               (insert "From:")
+               (setq from (point))
+               (insert "[no `from' set]\n"))
+             (while faces
+               (when (setq png (gnus-convert-face-to-png (pop faces)))
+                 (setq image
+                       (apply 'gnus-create-image png 'png t
+                              (cdr (assq 'png gnus-face-properties-alist))))
+                 (goto-char from)
+                 (gnus-add-wash-type 'face)
+                 (gnus-add-image 'face image)
+                 (gnus-put-image image nil 'face))))))))))
 
 (defun article-display-x-face (&optional force)
   "Look for an X-Face header and display it if present."
@@ -2190,13 +2205,10 @@ unfolded."
          (gnus-delete-images 'xface)
        ;; Display X-Faces.
        (let (x-faces from face)
-         (save-excursion
+         (save-current-buffer
            (when (and wash-face-p
-                      (progn
-                        (goto-char (point-min))
-                        (not (re-search-forward
-                              "^X-Face\\(-[0-9]+\\)?:[\t ]*" nil t)))
-                      (gnus-buffer-live-p gnus-original-article-buffer))
+                      (gnus-buffer-live-p gnus-original-article-buffer)
+                      (not (re-search-forward "^X-Face:[\t ]*" nil t)))
              ;; If type `W f', use gnus-original-article-buffer,
              ;; otherwise use the current buffer because displaying
              ;; RFC822 parts calls this function too.
@@ -2210,34 +2222,36 @@ unfolded."
          ;; single external face.
          (when (stringp gnus-article-x-face-command)
            (setq x-faces (list (car x-faces))))
-         (while (and (setq face (pop x-faces))
-                     gnus-article-x-face-command
-                     (or force
-                         ;; Check whether this face is censored.
-                         (not gnus-article-x-face-too-ugly)
-                         (and gnus-article-x-face-too-ugly from
-                              (not (string-match gnus-article-x-face-too-ugly
-                                                 from)))))
-           ;; We display the face.
-           (cond ((stringp gnus-article-x-face-command)
-                  ;; The command is a string, so we interpret the command
-                  ;; as a, well, command, and fork it off.
-                  (let ((process-connection-type nil))
-                    (process-kill-without-query
-                     (start-process
-                      "article-x-face" nil shell-file-name
-                      shell-command-switch gnus-article-x-face-command))
-                    (with-temp-buffer
-                      (insert face)
-                      (process-send-region "article-x-face"
-                                           (point-min) (point-max)))
-                    (process-send-eof "article-x-face")))
-                 ((functionp gnus-article-x-face-command)
-                  ;; The command is a lisp function, so we call it.
-                  (funcall gnus-article-x-face-command face))
-                 (t
-                  (error "%s is not a function"
-                         gnus-article-x-face-command)))))))))
+         (when (and x-faces
+                    gnus-article-x-face-command
+                    (or force
+                        ;; Check whether this face is censored.
+                        (not gnus-article-x-face-too-ugly)
+                        (and from
+                             (not (string-match gnus-article-x-face-too-ugly
+                                                from)))))
+           (while (setq face (pop x-faces))
+             ;; We display the face.
+             (cond ((stringp gnus-article-x-face-command)
+                    ;; The command is a string, so we interpret the command
+                    ;; as a, well, command, and fork it off.
+                    (let ((process-connection-type nil))
+                      (gnus-set-process-query-on-exit-flag
+                       (start-process
+                        "article-x-face" nil shell-file-name
+                        shell-command-switch gnus-article-x-face-command)
+                       nil)
+                      (with-temp-buffer
+                        (insert face)
+                        (process-send-region "article-x-face"
+                                             (point-min) (point-max)))
+                      (process-send-eof "article-x-face")))
+                   ((functionp gnus-article-x-face-command)
+                    ;; The command is a lisp function, so we call it.
+                    (funcall gnus-article-x-face-command face))
+                   (t
+                    (error "%s is not a function"
+                           gnus-article-x-face-command))))))))))
 
 (defun article-decode-mime-words ()
   "Decode all MIME-encoded words in the article."
@@ -2875,10 +2889,14 @@ how much time has lapsed since DATE.  For `lapsed', the value of
 should replace the \"Date:\" one, or should be added below it."
   (interactive (list 'ut t))
   (let* ((tdate-regexp "^Date:[ \t]\\|^X-Sent:[ \t]")
-        (date-regexp (if (and gnus-article-date-lapsed-new-header
-                              (eq type 'lapsed))
-                         "^X-Sent:[ \t]"
-                       tdate-regexp))
+        (date-regexp (cond ((not gnus-article-date-lapsed-new-header)
+                            tdate-regexp)
+                           ((eq type 'lapsed)
+                            "^X-Sent:[ \t]")
+                           (article-lapsed-timer
+                            "^Date:[ \t]")
+                           (t
+                            tdate-regexp)))
         (case-fold-search t)
         (inhibit-read-only t)
         (inhibit-point-motion-hooks t)
@@ -2887,23 +2905,15 @@ should replace the \"Date:\" one, or should be added below it."
       (save-restriction
        (widen)
        (goto-char (point-min))
-       (while (and (or (setq date (get-text-property (setq pos (point))
-                                                     'original-date))
-                       (and (setq pos (next-single-property-change
-                                       (point) 'original-date))
-                            (setq date (get-text-property pos
-                                                          'original-date))))
-                   (not (string-equal date "")))
-         (goto-char (or (text-property-any pos (point-max)
-                                           'original-date nil)
-                        (point-max)))
-         ;; Skip Face or X-Face.
-         (unless (bolp)
-           (end-of-line)
-           (goto-char (or (text-property-any pos (point-max)
-                                             'original-date nil)
-                          (point-max))))
-         (narrow-to-region pos (point))
+       (while (or (setq date (get-text-property (setq pos (point))
+                                                'original-date))
+                  (when (setq pos (next-single-property-change
+                                   (point) 'original-date))
+                    (setq date (get-text-property pos 'original-date))
+                    t))
+         (narrow-to-region pos (or (text-property-any pos (point-max)
+                                                      'original-date nil)
+                                   (point-max)))
          (goto-char (point-min))
          (when (re-search-forward tdate-regexp nil t)
            (setq bface (get-text-property (point-at-bol) 'face)
@@ -3079,20 +3089,21 @@ function and want to see what the date was before converting."
 
 (defun article-update-date-lapsed ()
   "Function to be run from a timer to update the lapsed time line."
-  (let (deactivate-mark)
-    (save-excursion
-      (ignore-errors
-       (walk-windows
-        (lambda (w)
-          (set-buffer (window-buffer w))
-          (when (eq major-mode 'gnus-article-mode)
-            (let ((mark (point-marker)))
-              (goto-char (point-min))
-              (when (re-search-forward "^X-Sent:" nil t)
-                (article-date-lapsed t))
-              (goto-char (marker-position mark))
-              (move-marker mark nil))))
-        nil 'visible)))))
+  (save-match-data
+    (let (deactivate-mark)
+      (save-excursion
+       (ignore-errors
+        (walk-windows
+         (lambda (w)
+           (set-buffer (window-buffer w))
+           (when (eq major-mode 'gnus-article-mode)
+             (let ((mark (point-marker)))
+               (goto-char (point-min))
+               (when (re-search-forward "^X-Sent:" nil t)
+                 (article-date-lapsed t))
+               (goto-char (marker-position mark))
+               (move-marker mark nil))))
+         nil 'visible))))))
 
 (defun gnus-start-date-timer (&optional n)
   "Start a timer to update the X-Sent header in the article buffers.
@@ -3123,21 +3134,26 @@ This format is defined by the `gnus-article-time-format' variable."
   (interactive (list t))
   (article-date-ut 'iso8601 highlight))
 
-(defun gnus-article-save-original-date ()
-  "Save the original date as a text property."
-  ;;(goto-char (point-max))
-  (skip-chars-backward "\n")
-  (let (start
-       (end (point))
-       (case-fold-search t))
-    (goto-char (point-min))
-    (when (and (re-search-forward "^date:[\t\n ]+" nil t)
-              (progn
-                (setq start (match-end 0))
-                (re-search-forward "[\t ]*\n\\(?:[^\t ]\\|\\'\\)" nil t)))
-      (put-text-property
-       (point-min) end 'original-date
-       (buffer-substring-no-properties start (match-beginning 0))))))
+(defmacro gnus-article-save-original-date (&rest forms)
+  "Save the original date as a text property and evaluate FORMS."
+  `(let* ((case-fold-search t)
+         (start (progn
+                  (goto-char (point-min))
+                  (when (and (re-search-forward "^date:[\t\n ]+" nil t)
+                             (not (bolp)))
+                    (match-end 0))))
+         (date (when (and start
+                          (re-search-forward "[\t ]*\n\\(?:[^\t ]\\|\\'\\)"
+                                             nil t))
+                 (buffer-substring-no-properties start
+                                                 (match-beginning 0)))))
+     (goto-char (point-max))
+     (skip-chars-backward "\n")
+     (put-text-property (point-min) (point) 'original-date date)
+     ,@forms
+     (goto-char (point-max))
+     (skip-chars-backward "\n")
+     (put-text-property (point-min) (point) 'original-date date)))
 
 ;; (defun article-show-all ()
 ;;   "Show all hidden text in the article buffer."
@@ -3749,6 +3765,7 @@ commands:
 \\[gnus-article-describe-briefly]\t Describe the current mode briefly
 \\[gnus-info-find-node]\t Go to the Gnus info node"
   (interactive)
+  (kill-all-local-variables)
   (gnus-simplify-mode-line)
   (setq mode-name "Article")
   (setq major-mode 'gnus-article-mode)
@@ -3771,14 +3788,14 @@ commands:
   (make-local-variable 'gnus-article-charset)
   (make-local-variable 'gnus-article-ignored-charsets)
   ;; Prevent recent Emacsen from displaying non-break space as "\ ".
-  (set (make-local-variable 'show-nonbreak-escape) nil)
+  (set (make-local-variable 'nobreak-char-display) nil)
   (gnus-set-default-directory)
   (buffer-disable-undo)
   (setq buffer-read-only t
        show-trailing-whitespace nil)
   (set-syntax-table gnus-article-mode-syntax-table)
   (mm-enable-multibyte)
-  (gnus-run-hooks 'gnus-article-mode-hook))
+  (gnus-run-mode-hooks 'gnus-article-mode-hook))
 
 (defun gnus-article-setup-buffer ()
   "Initialize the article buffer."
@@ -4082,6 +4099,7 @@ This function is exclusively used by `gnus-mime-save-part-and-strip'
 and `gnus-mime-delete-part', and not provided at run-time normally."
     (gnus-article-edit-article
      `(lambda ()
+       (buffer-disable-undo)
        (erase-buffer)
        (let ((mail-parse-charset (or gnus-article-charset
                                      ',gnus-newsgroup-charset))
@@ -4393,7 +4411,7 @@ Compressed files like .gz and .bz2 are decompressed."
                 (and charset
                      (setq coding-system
                            (mm-charset-to-coding-system charset))
-                     (not (eq charset 'ascii))))
+                     (not (eq coding-system 'ascii))))
             (mm-decode-coding-string contents coding-system)
           (mm-string-to-multibyte contents)))
        (goto-char b)))))
@@ -4676,7 +4694,7 @@ N is the numerical prefix."
          (set-window-point window point)))
       (let ((handles ihandles)
            (inhibit-read-only t)
-           handle name type b e display)
+           handle)
        (cond (handles)
              ((setq handles (mm-dissect-buffer nil gnus-article-loose-mime))
               (when gnus-article-emulate-mime
@@ -4715,8 +4733,8 @@ N is the numerical prefix."
            (save-restriction
              (article-goto-body)
              (narrow-to-region (point-min) (point))
-             (gnus-article-save-original-date)
-             (gnus-treat-article 'head))))))))
+             (gnus-article-save-original-date
+              (gnus-treat-article 'head)))))))))
 
 (defcustom gnus-mime-display-multipart-as-mixed nil
   "Display \"multipart\" parts as  \"multipart/mixed\".
@@ -6472,7 +6490,7 @@ do the highlighting.  See the documentation for those functions."
 (defun gnus-article-highlight-signature ()
   "Highlight the signature in an article.
 It does this by highlighting everything after
-`gnus-signature-separator' using `gnus-signature-face'."
+`gnus-signature-separator' using the face `gnus-signature'."
   (interactive)
   (gnus-with-article-buffer
     (let ((inhibit-point-motion-hooks t))
@@ -6765,7 +6783,7 @@ specified by `gnus-button-alist'."
                                     (match-string 3 address)
                                   "nntp")))
        nil nil nil
-       (and (match-end 6) (list (string-to-int (match-string 6 address))))))))
+       (and (match-end 6) (list (string-to-number (match-string 6 address))))))))
 
 (defun gnus-url-parse-query-string (query &optional downcase)
   (let (retval pairs cur key val)
@@ -7026,7 +7044,7 @@ For example:
     current-prefix-arg))
   (let ((func (cdr (assoc protocol gnus-article-encrypt-protocol-alist))))
     (unless func
-      (error (format "Can't find the encrypt protocol %s" protocol)))
+      (error "Can't find the encrypt protocol %s" protocol))
     (if (member gnus-newsgroup-name '("nndraft:delayed"
                                      "nndraft:drafts"
                                      "nndraft:queue"))