*** empty log message ***
[gnus] / lisp / gnus-cite.el
index f8901ab..6c70d44 100644 (file)
@@ -1,12 +1,7 @@
 ;;; gnus-cite.el --- parse citations in articles for Gnus
-;; Copyright (C) 1995,96 Free Software Foundation, Inc.
+;; Copyright (C) 1995,96,97,98,99 Free Software Foundation, Inc.
 
-;; Author: Per Abrahamsen <abraham@iesd.auc.dk>
-;; Keywords: news, mail
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; Author: Per Abhiddenware; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 ;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 ;; GNU General Public License for more details.
 
 ;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; 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.
 
 ;;; Commentary:
 
 ;;; Code:
 
-(require 'gnus)
-(require 'gnus-msg)
-(require 'gnus-ems)
+(eval-when-compile (require 'cl))
 
-(eval-and-compile
-  (autoload 'gnus-article-add-button "gnus-vis"))
+(require 'gnus)
+(require 'gnus-art)
+(require 'gnus-range)
 
 ;;; Customization:
 
-(defvar gnus-cite-parse-max-size 25000
+(defgroup gnus-cite nil
+  "Citation."
+  :prefix "gnus-cite-"
+  :link '(custom-manual "(gnus)Article Highlighting")
+  :group 'gnus-article)
+
+(defcustom gnus-cite-reply-regexp
+  "^\\(Subject: Re\\|In-Reply-To\\|References\\):"
+  "*If headers match this regexp it is reasonable to believe that
+article has citations."
+  :group 'gnus-cite
+  :type 'string)
+
+(defcustom gnus-cite-always-check nil
+  "Check article always for citations. Set it t to check all articles."
+  :group 'gnus-cite
+  :type '(choice (const :tag "no" nil)
+                 (const :tag "yes" t)))
+
+(defcustom gnus-cited-opened-text-button-line-format "%(%{[-]%}%)\n"
+  "Format of opened cited text buttons."
+  :group 'gnus-cite
+  :type 'string)
+
+(defcustom gnus-cited-closed-text-button-line-format "%(%{[+]%}%)\n"
+  "Format of closed cited text buttons."
+  :group 'gnus-cite
+  :type 'string)
+
+(defcustom gnus-cited-lines-visible nil
+  "The number of lines of hidden cited text to remain visible.
+Or a pair (cons) of numbers which are the number of lines at the top
+and bottom of the text, respectively, to remain visible."
+  :group 'gnus-cite
+  :type '(choice (const :tag "none" nil)
+                integer
+                (cons :tag "Top and Bottom" integer integer)))
+
+(defcustom gnus-cite-parse-max-size 25000
   "Maximum article size (in bytes) where parsing citations is allowed.
-Set it to nil to parse all articles.")
-
-(defvar gnus-cite-prefix-regexp 
-    "^[]>|:}+ ]*[]>|:}+]\\(.*>\\)?\\|^.*>"
-  "Regexp matching the longest possible citation prefix on a line.")
-
-(defvar gnus-cite-max-prefix 20
-  "Maximum possible length for a citation prefix.")
-
-(defvar gnus-supercite-regexp 
+Set it to nil to parse all articles."
+  :group 'gnus-cite
+  :type '(choice (const :tag "all" nil)
+                integer))
+
+(defcustom gnus-cite-prefix-regexp
+  "^[]>»|:}+ ]*[]>»|:}+]\\(.*>»\\)?\\|^.*>"
+  "*Regexp matching the longest possible citation prefix on a line."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-max-prefix 20
+  "Maximum possible length for a citation prefix."
+  :group 'gnus-cite
+  :type 'integer)
+
+(defcustom gnus-supercite-regexp
   (concat "^\\(" gnus-cite-prefix-regexp "\\)? *"
          ">>>>> +\"\\([^\"\n]+\\)\" +==")
-  "Regexp matching normal SuperCite attribution lines.
-The first grouping must match prefixes added by other packages.")
-
-(defvar gnus-supercite-secondary-regexp "^.*\"\\([^\"\n]+\\)\" +=="
-  "Regexp matching mangled SuperCite attribution lines.
-The first regexp group should match the SuperCite attribution.")
-
-(defvar gnus-cite-minimum-match-count 2
-  "Minimum number of identical prefixes before we believe it's a citation.")
-
-;see gnus-cus.el
-;(defvar gnus-cite-face-list 
-;  (if (eq gnus-display-type 'color)
-;      (if (eq gnus-background-mode 'dark) 'light 'dark)
-;    '(italic))
-;  "Faces used for displaying different citations.
-;It is either a list of face names, or one of the following special
-;values:
-
-;dark: Create faces from `gnus-face-dark-name-list'.
-;light: Create faces from `gnus-face-light-name-list'.
-
-;The variable `gnus-make-foreground' determines whether the created
-;faces change the foreground or the background colors.")
-
-(defvar gnus-cite-attribution-prefix "in article\\|in <"
-  "Regexp matching the beginning of an attribution line.")
-
-(defvar gnus-cite-attribution-suffix
-  "\\(wrote\\|writes\\|said\\|says\\):[ \t]*$"
-  "Regexp matching the end of an attribution line.
-The text matching the first grouping will be used as a button.")
-
-;see gnus-cus.el
-;(defvar gnus-cite-attribution-face 'underline
-;  "Face used for attribution lines.
-;It is merged with the face for the cited text belonging to the attribution.")
-
-;see gnus-cus.el
-;(defvar gnus-cite-hide-percentage 50
-;  "Only hide cited text if it is larger than this percent of the body.")
-
-;see gnus-cus.el
-;(defvar gnus-cite-hide-absolute 10
-;  "Only hide cited text if there is at least this number of cited lines.")
-
-;see gnus-cus.el
-;(defvar gnus-face-light-name-list
-;  '("light blue" "light cyan" "light yellow" "light pink"
-;    "pale green" "beige" "orange" "magenta" "violet" "medium purple"
-;    "turquoise")
-;  "Names of light colors.")
-
-;see gnus-cus.el
-;(defvar gnus-face-dark-name-list
-;  '("dark salmon" "firebrick"
-;    "dark green" "dark orange" "dark khaki" "dark violet"
-;    "dark turquoise")
-;  "Names of dark colors.")
+  "*Regexp matching normal Supercite attribution lines.
+The first grouping must match prefixes added by other packages."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-supercite-secondary-regexp "^.*\"\\([^\"\n]+\\)\" +=="
+  "Regexp matching mangled Supercite attribution lines.
+The first regexp group should match the Supercite attribution."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-minimum-match-count 2
+  "Minimum number of identical prefixes before we believe it's a citation."
+  :group 'gnus-cite
+  :type 'integer)
+
+(defcustom gnus-cite-attribution-prefix
+  "In article\\|in <\\|On \\(Mon\\|Tue\\|Wed\\|Thu\\|Fri\\|Sat\\|Sun\\),\\|-----Original Message-----"
+  "*Regexp matching the beginning of an attribution line."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defcustom gnus-cite-attribution-suffix
+  "\\(\\(wrote\\|writes\\|said\\|says\\|>\\)\\(:\\|\\.\\.\\.\\)\\|-----Original Message-----\\)[ \t]*$"
+  "*Regexp matching the end of an attribution line.
+The text matching the first grouping will be used as a button."
+  :group 'gnus-cite
+  :type 'regexp)
+
+(defface gnus-cite-attribution-face '((t
+                                      (:italic t)))
+  "Face used for attribution lines.")
+
+(defcustom gnus-cite-attribution-face 'gnus-cite-attribution-face
+  "Face used for attribution lines.
+It is merged with the face for the cited text belonging to the attribution."
+  :group 'gnus-cite
+  :type 'face)
+
+(defface gnus-cite-face-1 '((((class color)
+                             (background dark))
+                            (:foreground "light blue"))
+                           (((class color)
+                             (background light))
+                            (:foreground "MidnightBlue"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-2 '((((class color)
+                             (background dark))
+                            (:foreground "light cyan"))
+                           (((class color)
+                             (background light))
+                            (:foreground "firebrick"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-3 '((((class color)
+                             (background dark))
+                            (:foreground "light yellow"))
+                           (((class color)
+                             (background light))
+                            (:foreground "dark green"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-4 '((((class color)
+                             (background dark))
+                            (:foreground "light pink"))
+                           (((class color)
+                             (background light))
+                            (:foreground "OrangeRed"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-5 '((((class color)
+                             (background dark))
+                            (:foreground "pale green"))
+                           (((class color)
+                             (background light))
+                            (:foreground "dark khaki"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-6 '((((class color)
+                             (background dark))
+                            (:foreground "beige"))
+                           (((class color)
+                             (background light))
+                            (:foreground "dark violet"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-7 '((((class color)
+                             (background dark))
+                            (:foreground "orange"))
+                           (((class color)
+                             (background light))
+                            (:foreground "SteelBlue4"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-8 '((((class color)
+                             (background dark))
+                            (:foreground "magenta"))
+                           (((class color)
+                             (background light))
+                            (:foreground "magenta"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-9 '((((class color)
+                             (background dark))
+                            (:foreground "violet"))
+                           (((class color)
+                             (background light))
+                            (:foreground "violet"))
+                           (t
+                            (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-10 '((((class color)
+                              (background dark))
+                             (:foreground "medium purple"))
+                            (((class color)
+                              (background light))
+                             (:foreground "medium purple"))
+                            (t
+                             (:italic t)))
+  "Citation face.")
+
+(defface gnus-cite-face-11 '((((class color)
+                              (background dark))
+                             (:foreground "turquoise"))
+                            (((class color)
+                              (background light))
+                             (:foreground "turquoise"))
+                            (t
+                             (:italic t)))
+  "Citation face.")
+
+(defcustom gnus-cite-face-list
+  '(gnus-cite-face-1 gnus-cite-face-2 gnus-cite-face-3 gnus-cite-face-4
+    gnus-cite-face-5 gnus-cite-face-6 gnus-cite-face-7 gnus-cite-face-8
+    gnus-cite-face-9 gnus-cite-face-10 gnus-cite-face-11)
+  "*List of faces used for highlighting citations.
+
+When there are citations from multiple articles in the same message,
+Gnus will try to give each citation from each article its own face.
+This should make it easier to see who wrote what."
+  :group 'gnus-cite
+  :type '(repeat face))
+
+(defcustom gnus-cite-hide-percentage 50
+  "Only hide excess citation if above this percentage of the body."
+  :group 'gnus-cite
+  :type 'number)
+
+(defcustom gnus-cite-hide-absolute 10
+  "Only hide excess citation if above this number of lines in the body."
+  :group 'gnus-cite
+  :type 'integer)
 
 ;;; Internal Variables:
 
-(defvar gnus-article-length nil)
-;; Length of article last time we parsed it.
-;; BUG! KLUDGE! UGLY! FIX ME!
+(defvar gnus-cite-article nil)
+(defvar gnus-cite-overlay-list nil)
 
 (defvar gnus-cite-prefix-alist nil)
-;; Alist of citation prefixes.  
+;; Alist of citation prefixes.
 ;; The cdr is a list of lines with that prefix.
 
 (defvar gnus-cite-attribution-alist nil)
@@ -132,7 +282,18 @@ The text matching the first grouping will be used as a button.")
 ;; WROTE: is the attribution line number
 ;; IN: is the line number of the previous line if part of the same attribution,
 ;; PREFIX: Is the citation prefix of the attribution line(s), and
-;; TAG: Is a SuperCite tag, if any.
+;; TAG: Is a Supercite tag, if any.
+
+(defvar gnus-cited-opened-text-button-line-format-alist
+  `((?b (marker-position beg) ?d)
+    (?e (marker-position end) ?d)
+    (?n (count-lines beg end) ?d)
+    (?l (- end beg) ?d)))
+(defvar gnus-cited-opened-text-button-line-format-spec nil)
+(defvar gnus-cited-closed-text-button-line-format-alist
+  gnus-cited-opened-text-button-line-format-alist)
+(defvar gnus-cited-closed-text-button-line-format-spec nil)
+
 
 ;;; Commands:
 
@@ -144,18 +305,11 @@ Attribution lines are highlighted with the same face as the
 corresponding citation merged with `gnus-cite-attribution-face'.
 
 Text is considered cited if at least `gnus-cite-minimum-match-count'
-lines matches `gnus-cite-prefix-regexp' with the same prefix.  
+lines matches `gnus-cite-prefix-regexp' with the same prefix.
 
 Lines matching `gnus-cite-attribution-suffix' and perhaps
 `gnus-cite-attribution-prefix' are considered attribution lines."
   (interactive (list 'force))
-  ;; Create dark or light faces if necessary.
-  (cond ((eq gnus-cite-face-list 'light)
-        (setq gnus-cite-face-list
-              (mapcar 'gnus-make-face gnus-face-light-name-list)))
-       ((eq gnus-cite-face-list 'dark)
-        (setq gnus-cite-face-list
-              (mapcar 'gnus-make-face gnus-face-dark-name-list))))
   (save-excursion
     (set-buffer gnus-article-buffer)
     (gnus-cite-parse-maybe force)
@@ -189,12 +343,13 @@ Lines matching `gnus-cite-attribution-suffix' and perhaps
              skip (gnus-cite-find-prefix number)
              face (cdr (assoc prefix face-alist)))
        ;; Add attribution button.
-       (goto-line number)
-       (if (re-search-forward gnus-cite-attribution-suffix 
-                              (save-excursion (end-of-line 1) (point))
-                              t)
-           (gnus-article-add-button (match-beginning 1) (match-end 1)
-                                    'gnus-cite-toggle prefix))
+       (goto-char (point-min))
+       (forward-line (1- number))
+       (when (re-search-forward gnus-cite-attribution-suffix
+                                (save-excursion (end-of-line 1) (point))
+                                t)
+         (gnus-article-add-button (match-beginning 1) (match-end 1)
+                                  'gnus-cite-toggle prefix))
        ;; Highlight attribution line.
        (gnus-cite-add-face number skip face)
        (gnus-cite-add-face number skip gnus-cite-attribution-face))
@@ -207,17 +362,13 @@ Lines matching `gnus-cite-attribution-suffix' and perhaps
              skip (gnus-cite-find-prefix number))
        (gnus-cite-add-face number skip gnus-cite-attribution-face)))))
 
-(defun gnus-article-fill-cited-article (&optional force)
-  "Do word wrapping in the current article."
-  (interactive (list t))
+(defun gnus-dissect-cited-text ()
+  "Dissect the article buffer looking for cited text."
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe force)
-    (let ((buffer-read-only nil)
-         (alist gnus-cite-prefix-alist)
-         (inhibit-point-motion-hooks t)
-         prefix numbers number marks
-         (adaptive-fill-mode nil))
+    (gnus-cite-parse-maybe nil t)
+    (let ((alist gnus-cite-prefix-alist)
+         prefix numbers number marks m)
       ;; Loop through citation prefixes.
       (while alist
        (setq numbers (pop alist)
@@ -233,14 +384,16 @@ Lines matching `gnus-cite-attribution-suffix' and perhaps
          (goto-char (point-min))
          (forward-line (1- number))
          (push (cons (point-marker) prefix) marks)))
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      ;; Skip to the beginning of the body.
+      (article-goto-body)
       (push (cons (point-marker) "") marks)
+      ;; Find the end of the body.
       (goto-char (point-max))
-      (re-search-backward gnus-signature-separator nil t)
+      (gnus-article-search-signature)
       (push (cons (point-marker) "") marks)
-      (setq marks (sort marks (lambda (m1 m2) (< (car m1) (car m2)))))
-      (let* ((omarks marks))
+      ;; Sort the marks.
+      (setq marks (sort marks 'car-less-than-car))
+      (let ((omarks marks))
        (setq marks nil)
        (while (cdr omarks)
          (if (= (caar omarks) (caadr omarks))
@@ -249,51 +402,157 @@ Lines matching `gnus-cite-attribution-suffix' and perhaps
                  (push (car omarks) marks))
                (unless (equal (cdadr omarks) "")
                  (push (cadr omarks) marks))
-               (setq omarks (cdr omarks)))
+               (unless (and (equal (cdar omarks) "")
+                            (equal (cdadr omarks) "")
+                            (not (cddr omarks)))
+                 (setq omarks (cdr omarks))))
            (push (car omarks) marks))
          (setq omarks (cdr omarks)))
-       (push (car omarks) marks)
-       (setq marks (nreverse marks)))
+       (when (car omarks)
+         (push (car omarks) marks))
+       (setq marks (setq m (nreverse marks)))
+       (while (cddr m)
+         (if (and (equal (cdadr m) "")
+                  (equal (cdar m) (cdaddr m))
+                  (goto-char (caadr m))
+                  (forward-line 1)
+                  (= (point) (caaddr m)))
+             (setcdr m (cdddr m))
+           (setq m (cdr m))))
+       marks))))
+
+(defun gnus-article-fill-cited-article (&optional force width)
+  "Do word wrapping in the current article.
+If WIDTH (the numerical prefix), use that text width when filling."
+  (interactive (list t current-prefix-arg))
+  (save-excursion
+    (set-buffer gnus-article-buffer)
+    (let ((buffer-read-only nil)
+         (inhibit-point-motion-hooks t)
+         (marks (gnus-dissect-cited-text))
+         (adaptive-fill-mode nil)
+         (filladapt-mode nil)
+         (fill-column (if width (prefix-numeric-value width) fill-column)))
       (save-restriction
        (while (cdr marks)
-         (widen)
-         (narrow-to-region (car (car marks)) (car (cadr marks)))
-         (let ((adaptive-fill-regexp (concat "^" (regexp-quote
-                                                  (cdr (car marks)))
-                                             " *"))
-               (fill-prefix (cdr (car marks)))
-               )
+         (narrow-to-region (caar marks) (caadr marks))
+         (let ((adaptive-fill-regexp
+                (concat "^" (regexp-quote (cdar marks)) " *"))
+               (fill-prefix (cdar marks)))
            (fill-region (point-min) (point-max)))
          (set-marker (caar marks) nil)
          (setq marks (cdr marks)))
-       (set-marker (caar marks) nil)))))
+       (when marks
+         (set-marker (caar marks) nil))
+       ;; All this information is now incorrect.
+       (setq gnus-cite-prefix-alist nil
+             gnus-cite-attribution-alist nil
+             gnus-cite-loose-prefix-alist nil
+             gnus-cite-loose-attribution-alist nil
+             gnus-cite-article nil)))))
 
 (defun gnus-article-hide-citation (&optional arg force)
   "Toggle hiding of all cited text except attribution lines.
 See the documentation for `gnus-article-highlight-citation'.
 If given a negative prefix, always show; if given a positive prefix,
 always hide."
-  (interactive (list current-prefix-arg 'force))
-  (unless (gnus-article-check-hidden-text 'cite arg)
-    (save-excursion
-      (set-buffer gnus-article-buffer)
-      (gnus-cite-parse-maybe force)
+  (interactive (append (gnus-article-hidden-arg) (list 'force)))
+  (gnus-set-format 'cited-opened-text-button t)
+  (gnus-set-format 'cited-closed-text-button t)
+  (save-excursion
+    (set-buffer gnus-article-buffer)
+    (cond
+     ((gnus-article-check-hidden-text 'cite arg)
+      t)
+     ((gnus-article-text-type-exists-p 'cite)
+      (let ((buffer-read-only nil))
+       (gnus-article-hide-text-of-type 'cite)))
+     (t
       (let ((buffer-read-only nil)
-           (alist gnus-cite-prefix-alist)
+           (marks (gnus-dissect-cited-text))
            (inhibit-point-motion-hooks t)
-           numbers number)
-       (while alist
-         (setq numbers (cdr (car alist))
-               alist (cdr alist))
-         (while numbers
-           (setq number (car numbers)
-                 numbers (cdr numbers))
-           (goto-line number)
-           (or (assq number gnus-cite-attribution-alist)
-               (add-text-properties 
-                (point) (progn (forward-line 1) (point))
-                (nconc (list 'gnus-type 'cite)
-                       gnus-hidden-properties)))))))))
+           (props (nconc (list 'article-type 'cite)
+                         gnus-hidden-properties))
+           beg end start)
+       (while marks
+         (setq beg nil
+               end nil)
+         (while (and marks (string= (cdar marks) ""))
+           (setq marks (cdr marks)))
+         (when marks
+           (setq beg (caar marks)))
+         (while (and marks (not (string= (cdar marks) "")))
+           (setq marks (cdr marks)))
+         (when marks
+           (setq end (caar marks)))
+         ;; Skip past lines we want to leave visible.
+         (when (and beg end gnus-cited-lines-visible)
+           (goto-char beg)
+           (forward-line (if (consp gnus-cited-lines-visible)
+                             (car gnus-cited-lines-visible)
+                           gnus-cited-lines-visible))
+           (if (>= (point) end)
+               (setq beg nil)
+             (setq beg (point-marker))
+             (when (consp gnus-cited-lines-visible)
+               (goto-char end)
+               (forward-line (- (cdr gnus-cited-lines-visible)))
+               (if (<= (point) beg)
+                   (setq beg nil)
+                 (setq end (point-marker))))))
+         (when (and beg end)
+           ;; We use markers for the end-points to facilitate later
+           ;; wrapping and mangling of text.
+           (setq beg (set-marker (make-marker) beg)
+                 end (set-marker (make-marker) end))
+           (gnus-add-text-properties beg end props)
+           (goto-char beg)
+           (unless (save-excursion (search-backward "\n\n" nil t))
+             (insert "\n"))
+           (put-text-property
+            (setq start (point-marker))
+            (progn
+              (gnus-article-add-button
+               (point)
+               (progn (eval gnus-cited-closed-text-button-line-format-spec)
+                      (point))
+               `gnus-article-toggle-cited-text
+               (list (cons beg end) start))
+              (point))
+            'article-type 'annotation)
+           (set-marker beg (point)))))))))
+
+(defun gnus-article-toggle-cited-text (args)
+  "Toggle hiding the text in REGION."
+  (let* ((region (car args))
+        (start (cadr args))
+        (hidden
+         (text-property-any
+          (car region) (1- (cdr region))
+          (car gnus-hidden-properties) (cadr gnus-hidden-properties)))
+        (inhibit-point-motion-hooks t)
+        buffer-read-only)
+    (funcall
+     (if hidden
+        'remove-text-properties 'gnus-add-text-properties)
+     (car region) (cdr region) gnus-hidden-properties)
+    (save-excursion
+      (goto-char start)
+      (gnus-delete-line)
+      (put-text-property
+       (point)
+       (progn
+        (gnus-article-add-button
+         (point)
+         (progn (eval
+                 (if hidden
+                     gnus-cited-opened-text-button-line-format-spec
+                   gnus-cited-closed-text-button-line-format-spec))
+                (point))
+         `gnus-article-toggle-cited-text
+         args)
+        (point))
+       'article-type 'annotation))))
 
 (defun gnus-article-hide-citation-maybe (&optional arg force)
   "Toggle hiding of cited text that has an attribution line.
@@ -304,44 +563,42 @@ percent and at least `gnus-cite-hide-absolute' lines of the body is
 cited text with attributions.  When called interactively, these two
 variables are ignored.
 See also the documentation for `gnus-article-highlight-citation'."
-  (interactive (list current-prefix-arg 'force))
+  (interactive (append (gnus-article-hidden-arg) '(force)))
   (unless (gnus-article-check-hidden-text 'cite arg)
     (save-excursion
       (set-buffer gnus-article-buffer)
       (gnus-cite-parse-maybe force)
-      (goto-char (point-min))
-      (search-forward "\n\n" nil t)
+      (article-goto-body)
       (let ((start (point))
            (atts gnus-cite-attribution-alist)
            (buffer-read-only nil)
            (inhibit-point-motion-hooks t)
-           (hiden 0)
+           (hidden 0)
            total)
        (goto-char (point-max))
-       (re-search-backward gnus-signature-separator nil t)
+       (gnus-article-search-signature)
        (setq total (count-lines start (point)))
        (while atts
-         (setq hiden (+ hiden (length (cdr (assoc (cdr (car atts))
-                                                  gnus-cite-prefix-alist))))
+         (setq hidden (+ hidden (length (cdr (assoc (cdar atts)
+                                                    gnus-cite-prefix-alist))))
                atts (cdr atts)))
-       (if (or force
-