Remove dead code
[gnus] / lisp / gnus-score.el
index 29d0df5..f24d889 100644 (file)
@@ -1,6 +1,6 @@
 ;;; gnus-score.el --- scoring code for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-;;        Free Software Foundation, Inc.
+
+;; Copyright (C) 1995-2012 Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk>
 ;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -8,10 +8,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: 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.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -19,9 +19,7 @@
 ;; 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, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -36,8 +34,6 @@
 (require 'message)
 (require 'score-mode)
 
-(autoload 'ffap-string-at-point "ffap")
-
 (defcustom gnus-global-score-files nil
   "List of global score files and directories.
 Set this variable if you want to use people's score files.  One entry
@@ -141,16 +137,22 @@ If this variable is nil, no score file entries will be expired."
                 number))
 
 (defcustom gnus-update-score-entry-dates t
-  "*In non-nil, update matching score entry dates.
+  "*If non-nil, update matching score entry dates.
 If this variable is nil, then score entries that provide matches
 will be expired along with non-matching score entries."
   :group 'gnus-score-expire
   :type 'boolean)
 
 (defcustom gnus-decay-scores nil
-  "*If non-nil, decay non-permanent scores."
+  "*If non-nil, decay non-permanent scores.
+
+If it is a regexp, only decay score files matching regexp."
   :group 'gnus-score-decay
-  :type 'boolean)
+  :type `(choice (const :tag "never" nil)
+                (const :tag "always" t)
+                (const :tag "adaptive score files"
+                       ,(concat "\\." gnus-adaptive-file-suffix "\\'"))
+                (regexp)))
 
 (defcustom gnus-decay-score-function 'gnus-decay-score
   "*Function called to decay a score.
@@ -174,7 +176,7 @@ It is called with one parameter -- the score to be decayed."
 It can be:
 
  * A string
-   This file file will be used as the home score file.
+   This file will be used as the home score file.
 
  * A function
    The result of this function will be used as the home score file.
@@ -185,7 +187,7 @@ It can be:
    The elements in this list can be:
 
    * `(regexp file-name ...)'
-     If the `regexp' matches the group name, the first `file-name' will
+     If the `regexp' matches the group name, the first `file-name'
      will be used as the home score file.  (Multiple filenames are
      allowed so that one may use gnus-score-file-single-match-alist to
      set this variable.)
@@ -203,10 +205,10 @@ It can be:
   :type '(choice string
                 (repeat (choice string
                                 (cons regexp (repeat file))
-                                (function :value fun)))
+                                function))
                 (function-item gnus-hierarchial-home-score-file)
                 (function-item gnus-current-home-score-file)
-                (function :value fun)))
+                function))
 
 (defcustom gnus-home-adapt-file nil
   "Variable to control where new adaptive score entries are to go.
@@ -216,17 +218,26 @@ This variable allows the same syntax as `gnus-home-score-file'."
   :type '(choice string
                 (repeat (choice string
                                 (cons regexp (repeat file))
-                                (function :value fun)))
-                (function :value fun)))
+                                function))
+                function))
 
 (defcustom gnus-default-adaptive-score-alist
-  '((gnus-kill-file-mark)
+  `((gnus-kill-file-mark)
     (gnus-unread-mark)
-    (gnus-read-mark (from 3) (subject 30))
-    (gnus-catchup-mark (subject -10))
-    (gnus-killed-mark (from -1) (subject -20))
-    (gnus-del-mark (from -2) (subject -15)))
-  "*Alist of marks and scores."
+    (gnus-read-mark
+     (from , (+ 2 gnus-score-decay-constant))
+     (subject , (+ 27 gnus-score-decay-constant)))
+    (gnus-catchup-mark
+     (subject , (+ -7 (* -1 gnus-score-decay-constant))))
+    (gnus-killed-mark
+     (from , (- -1 gnus-score-decay-constant))
+     (subject , (+ -17 (* -1 gnus-score-decay-constant))))
+    (gnus-del-mark
+     (from , (- -1 gnus-score-decay-constant))
+     (subject , (+ -12 (* -1 gnus-score-decay-constant)))))
+  "Alist of marks and scores.
+If you use score decays, you might want to set values higher than
+`gnus-score-decay-constant'."
   :group 'gnus-score-adapt
   :type '(repeat (cons (symbol :tag "Mark")
                       (repeat (list (choice :tag "Header"
@@ -237,9 +248,10 @@ This variable allows the same syntax as `gnus-home-score-file'."
 
 (defcustom gnus-adaptive-word-length-limit nil
   "*Words of a length lesser than this limit will be ignored when doing adaptive scoring."
+  :version "22.1"
   :group 'gnus-score-adapt
   :type '(radio (const :format "Unlimited " nil)
-               (integer :format "Maximum length: %v\n" :size 0)))
+               (integer :format "Maximum length: %v")))
 
 (defcustom gnus-ignored-adaptive-words nil
   "List of words to be ignored when doing adaptive word scoring."
@@ -307,6 +319,13 @@ If this variable is nil, exact matching will always be used."
   :group 'gnus-score-files
   :type 'regexp)
 
+(defcustom gnus-adaptive-pretty-print nil
+  "If non-nil, adaptive score files fill are pretty printed."
+  :group 'gnus-score-files
+  :group 'gnus-score-adapt
+  :version "23.1" ;; No Gnus
+  :type 'boolean)
+
 (defcustom gnus-score-default-header nil
   "Default header when entering new scores.
 
@@ -370,7 +389,7 @@ If nil, the user will be asked for a match type."
                 (const :tag "ask" nil)))
 
 (defcustom gnus-score-default-fold nil
-  "Use case folding for new score file entries iff not nil."
+  "Non-nil means use case folding for new score file entries."
   :group 'gnus-score-default
   :type 'boolean)
 
@@ -400,6 +419,18 @@ If nil, the user will be asked for a duration."
   :group 'gnus-score-various
   :type 'boolean)
 
+(defcustom gnus-inhibit-slow-scoring nil
+  "Inhibit slow scoring, e.g. scoring on headers or body.
+
+If a regexp, scoring on headers or body is inhibited if the group
+matches the regexp.  If it is t, scoring on headers or body is
+inhibited for all groups."
+  :group 'gnus-score-various
+  :version "23.1" ;; No Gnus
+  :type '(choice (const :tag "All" nil)
+                (const :tag "None" t)
+                regexp))
+
 \f
 
 ;; Internal variables.
@@ -491,9 +522,10 @@ of the last successful match.")
 (defun gnus-summary-lower-score (&optional score symp)
   "Make a score entry based on the current article.
 The user will be prompted for header to score on, match type,
-permanence, and the string to be used.  The numerical prefix will be
-used as score.  A symbolic prefix of `a' says to use the `all.SCORE'
-file for the command instead of the current score file."
+permanence, and the string to be used.  The numerical prefix will
+be used as SCORE.  A symbolic prefix of `a' (the SYMP parameter)
+says to use the `all.SCORE' file for the command instead of the
+current score file."
   (interactive (gnus-interactive "P\ny"))
   (gnus-summary-increase-score (- (gnus-score-delta-default score)) symp))
 
@@ -506,9 +538,10 @@ file for the command instead of the current score file."
 (defun gnus-summary-increase-score (&optional score symp)
   "Make a score entry based on the current article.
 The user will be prompted for header to score on, match type,
-permanence, and the string to be used.  The numerical prefix will be
-used as score.  A symbolic prefix of `a' says to use the `all.SCORE'
-file for the command instead of the current score file."
+permanence, and the string to be used.  The numerical prefix will
+be used as SCORE.  A symbolic prefix of `a' (the SYMP parameter)
+says to use the `all.SCORE' file for the command instead of the
+current score file."
   (interactive (gnus-interactive "P\ny"))
   (let* ((nscore (gnus-score-delta-default score))
         (prefix (if (< nscore 0) ?L ?I))
@@ -627,7 +660,7 @@ file for the command instead of the current score file."
              (gnus-score-insert-help "Match permanence" char-to-perm 2)))
 
          (gnus-score-kill-help-buffer)
-         (if mimic (message "%c %c %c" prefix hchar tchar pchar)
+         (if mimic (message "%c %c %c %c" prefix hchar tchar pchar)
            (message ""))
          (unless (setq temporary (cadr (assq pchar char-to-perm)))
            ;; Deal with der(r)ided superannuated paradigms.
@@ -648,14 +681,14 @@ file for the command instead of the current score file."
          (and gnus-extra-headers
               (equal (nth 1 entry) "extra")
               (intern                  ; need symbol
-               (gnus-completing-read-with-default
-                (symbol-name (car gnus-extra-headers)) ; default response
-                "Score extra header:"  ; prompt
-                (mapcar (lambda (x)    ; completion list
-                          (cons (symbol-name x) x))
-                        gnus-extra-headers)
-                nil                    ; no completion limit
-                t))))                  ; require match
+                (let ((collection (mapcar 'symbol-name gnus-extra-headers)))
+                  (gnus-completing-read
+                   "Score extra header"  ; prompt
+                   collection            ; completion list
+                   t                     ; require match
+                   nil                   ; no history
+                   nil                   ; no initial-input
+                   (car collection)))))) ; default value
     ;; extra is now nil or a symbol.
 
     ;; We have all the data, so we enter this score.
@@ -676,8 +709,7 @@ file for the command instead of the current score file."
 
     ;; Change score file to the "all.SCORE" file.
     (when (eq symp 'a)
-      (save-excursion
-       (set-buffer gnus-summary-buffer)
+      (with-current-buffer gnus-summary-buffer
        (gnus-score-load-file
         ;; This is a kludge; yes...
         (cond
@@ -703,14 +735,12 @@ file for the command instead of the current score file."
 
     (when (eq symp 'a)
       ;; We change the score file back to the previous one.
-      (save-excursion
-       (set-buffer gnus-summary-buffer)
+      (with-current-buffer gnus-summary-buffer
        (gnus-score-load-file current-score-file)))))
 
 (defun gnus-score-insert-help (string alist idx)
   (setq gnus-score-help-winconf (current-window-configuration))
-  (save-excursion
-    (set-buffer (gnus-get-buffer-create "*Score Help*"))
+  (with-current-buffer (gnus-get-buffer-create "*Score Help*")
     (buffer-disable-undo)
     (delete-windows-on (current-buffer))
     (erase-buffer)
@@ -742,7 +772,7 @@ file for the command instead of the current score file."
        (setq i (1+ i))))
     (goto-char (point-min))
     ;; display ourselves in a small window at the bottom
-    (gnus-appt-select-lowest-window)
+    (gnus-select-lowest-window)
     (if (< (/ (window-height) 2) window-min-height)
        (switch-to-buffer "*Score Help*")
       (split-window)
@@ -825,7 +855,7 @@ If optional argument `EXTRA' is non-nil, it's a non-standard overview header."
     ;; If this is an integer comparison, we transform from string to int.
     (if (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer)
        (if (stringp match)
-           (setq match (string-to-int match)))
+           (setq match (string-to-number match)))
       (set-text-properties 0 (length match) nil match))
 
     (unless (eq date 'now)
@@ -884,13 +914,16 @@ MATCH is the string we are looking for.
 TYPE is the score type.
 SCORE is the score to add.
 EXTRA is the possible non-standard header."
-  (interactive (list (completing-read "Header: "
-                                     gnus-header-index
-                                     (lambda (x) (fboundp (nth 2 x)))
-                                     t)
+  (interactive (list (gnus-completing-read "Header"
+                                           (mapcar
+                                            'car
+                                            (gnus-remove-if-not
+                                             (lambda (x) (fboundp (nth 2 x)))
+                                             gnus-header-index))
+                                           t)
                     (read-string "Match: ")
                     (if (y-or-n-p "Use regexp match? ") 'r 's)
-                    (string-to-int (read-string "Score: "))))
+                    (string-to-number (read-string "Score: "))))
   (save-excursion
     (unless (and (stringp match) (> (length match) 0))
       (error "No match"))
@@ -914,25 +947,6 @@ EXTRA is the possible non-standard header."
                 (gnus-summary-raise-score score))))
        (beginning-of-line 2))))
   (gnus-set-mode-line 'summary))
-
-(defun gnus-summary-score-crossposting (score date)
-  ;; Enter score file entry for current crossposting.
-  ;; SCORE is the score to add.
-  ;; DATE is the expire date.
-  (let ((xref (gnus-summary-header "xref"))
-       (start 0)
-       group)
-    (unless xref
-      (error "This article is not crossposted"))
-    (while (string-match " \\([^ \t]+\\):" xref start)
-      (setq start (match-end 0))
-      (when (not (string=
-                 (setq group
-                       (substring xref (match-beginning 1) (match-end 1)))
-                 gnus-newsgroup-name))
-       (gnus-summary-score-entry
-        "xref" (concat " " group ":") nil score date t)))))
-
 \f
 ;;;
 ;;; Gnus Score Files
@@ -944,7 +958,7 @@ EXTRA is the possible non-standard header."
   "Automatically mark articles with score below SCORE as read."
   (interactive
    (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg))
-            (string-to-int (read-string "Mark below: ")))))
+            (string-to-number (read-string "Mark below: ")))))
   (setq score (or score gnus-summary-default-score 0))
   (gnus-score-set 'mark (list score))
   (gnus-score-set 'touched '(t))
@@ -978,7 +992,7 @@ EXTRA is the possible non-standard header."
   "Automatically expunge articles with score below SCORE."
   (interactive
    (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg))
-            (string-to-int (read-string "Set expunge below: ")))))
+            (string-to-number (read-string "Set expunge below: ")))))
   (setq score (or score gnus-summary-default-score 0))
   (gnus-score-set 'expunge (list score))
   (gnus-score-set 'touched '(t)))
@@ -1085,13 +1099,18 @@ EXTRA is the possible non-standard header."
       (make-local-variable 'gnus-prev-winconf)
       (setq gnus-prev-winconf winconf))
     (gnus-message
-     4 (substitute-command-keys
-       "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits"))))
+     4 "%s" (substitute-command-keys
+            "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits"))))
 
-(defun gnus-score-edit-all-score (file)
+(defun gnus-score-edit-all-score ()
   "Edit the all.SCORE file."
   (interactive)
-  (find-file (gnus-score-file-name "all")))
+  (find-file (gnus-score-file-name "all"))
+  (gnus-score-mode)
+  (setq gnus-score-edit-exit-function 'gnus-score-edit-done)
+  (gnus-message
+   4 (substitute-command-keys
+      "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits")))
 
 (defun gnus-score-edit-file (file)
   "Edit a score file."
@@ -1108,8 +1127,8 @@ EXTRA is the possible non-standard header."
     (make-local-variable 'gnus-prev-winconf)
     (setq gnus-prev-winconf winconf))
   (gnus-message
-   4 (substitute-command-keys
-      "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits")))
+   4 "%s" (substitute-command-keys
+          "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits")))
 
 (defun gnus-score-edit-file-at-point (&optional format)
   "Edit score file at point in Score Trace buffers.
@@ -1203,7 +1222,9 @@ If FORMAT, also format the current score file."
          (decay (car (gnus-score-get 'decay alist)))
          (eval (car (gnus-score-get 'eval alist))))
       ;; Perform possible decays.
-      (when (and gnus-decay-scores
+      (when (and (if (stringp gnus-decay-scores)
+                    (string-match gnus-decay-scores file)
+                  gnus-decay-scores)
                 (or cached (file-exists-p file))
                 (or (not decay)
                     (gnus-decay-scores alist decay)))
@@ -1213,8 +1234,7 @@ If FORMAT, also format the current score file."
       ;; files.
       (when (and files (not global))
        (setq lists (apply 'append lists
-                          (mapcar (lambda (file)
-                                    (gnus-score-load-file file))
+                          (mapcar 'gnus-score-load-file
                                   (if adapt-file (cons adapt-file files)
                                     files)))))
       (when (and eval (not global))
@@ -1232,8 +1252,7 @@ If FORMAT, also format the current score file."
               exclude-files))
             gnus-scores-exclude-files))
       (when local
-       (save-excursion
-         (set-buffer gnus-summary-buffer)
+       (with-current-buffer gnus-summary-buffer
          (while local
            (and (consp (car local))
                 (symbolp (caar local))
@@ -1357,7 +1376,7 @@ If FORMAT, also format the current score file."
       (if err
          (progn
            (ding)
-           (gnus-message 3 err)
+           (gnus-message 3 "%s" err)
            (sit-for 2)
            nil)
        alist)))))
@@ -1406,17 +1425,18 @@ If FORMAT, also format the current score file."
          (setq score (setcdr entry (gnus-delete-alist 'touched score)))
          (erase-buffer)
          (let (emacs-lisp-mode-hook)
-           (if (string-match
-                (concat (regexp-quote gnus-adaptive-file-suffix) "$")
-                file)
-               ;; This is an adaptive score file, so we do not run
-               ;; it through `pp'.  These files can get huge, and
-               ;; are not meant to be edited by human hands.
+           (if (and (not gnus-adaptive-pretty-print)
+                    (string-match
+                     (concat (regexp-quote gnus-adaptive-file-suffix) "$")
+                     file))
+               ;; This is an adaptive score file, so we do not run it through
+               ;; `pp' unless requested.  These files can get huge, and are
+               ;; not meant to be edited by human hands.
                (gnus-prin1 score)
              ;; This is a normal score file, so we print it very
              ;; prettily.
              (let ((lisp-mode-syntax-table score-mode-syntax-table))
-               (pp score (current-buffer)))))
+               (gnus-pp score))))
          (gnus-make-directory (file-name-directory file))
          ;; If the score file is empty, we delete it.
          (if (zerop (buffer-size))
@@ -1489,8 +1509,7 @@ If FORMAT, also format the current score file."
                    (cons (cons header (or gnus-summary-default-score 0))
                          gnus-scores-articles))))
 
-         (save-excursion
-           (set-buffer (gnus-get-buffer-create "*Headers*"))
+         (with-current-buffer (gnus-get-buffer-create "*Headers*")
            (buffer-disable-undo)
            (when (gnus-buffer-live-p gnus-summary-buffer)
              (message-clone-locals gnus-summary-buffer))
@@ -1511,9 +1530,22 @@ If FORMAT, also format the current score file."
                                      (lambda (score)
                                        (length (gnus-score-get header score)))
                                      scores)))
-               ;; Call the scoring function for this type of "header".
-               (when (setq new (funcall (nth 2 entry) scores header
-                                        now expire trace))
+               (when (if (and gnus-inhibit-slow-scoring
+                              (or (eq gnus-inhibit-slow-scoring t)
+                                  (and (stringp gnus-inhibit-slow-scoring)
+                                       ;; Always true here?
+                                       ;; (stringp gnus-newsgroup-name)
+                                       (string-match
+                                        gnus-inhibit-slow-scoring
+                                        gnus-newsgroup-name)))
+                              (> 0 (nth 1 (assoc header gnus-header-index))))
+                         (progn
+                           (gnus-message
+                            7 "Scoring on headers or body skipped.")
+                           nil)
+                       ;; Call the scoring function for this type of "header".
+                       (setq new (funcall (nth 2 entry) scores header
+                                          now expire trace)))
                  (push new news))))
            (when (gnus-buffer-live-p gnus-summary-buffer)
              (let ((scored gnus-newsgroup-scored))
@@ -1802,8 +1834,7 @@ score in `gnus-newsgroup-scored' by SCORE."
 
       ;; Change score file to the adaptive score file.  All entries that
       ;; this function makes will be put into this file.
-      (save-excursion
-       (set-buffer gnus-summary-buffer)
+      (with-current-buffer gnus-summary-buffer
        (gnus-score-load-file
         (or gnus-newsgroup-adaptive-score-file
             (gnus-score-file-name
@@ -1894,15 +1925,13 @@ score in `gnus-newsgroup-scored' by SCORE."
                   (setq rest entries)))
            (setq entries rest))))
       ;; We change the score file back to the previous one.
-      (save-excursion
-       (set-buffer gnus-summary-buffer)
+      (with-current-buffer gnus-summary-buffer
        (gnus-score-load-file current-score-file))
       (list (cons "references" news)))))
 
 (defun gnus-score-add-followups (header score scores &optional thread)
   "Add a score entry to the adapt file."
-  (save-excursion
-    (set-buffer gnus-summary-buffer)
+  (with-current-buffer gnus-summary-buffer
     (let* ((id (mail-header-id header))
           (scores (car scores))
           entry dont)
@@ -2003,8 +2032,11 @@ score in `gnus-newsgroup-scored' by SCORE."
 
          ;; Evil hackery to make match usable in non-standard headers.
          (when extra
-           (setq match (concat "[ (](" extra " \\. \"[^)]*"
-                               match "[^\"]*\")[ )]")
+           (setq match (concat "[ (](" extra " \\. \"\\([^\"]*\\\\\"\\)*[^\"]*"
+                               (if (eq search-func 're-search-forward)
+                                   match
+                                 (regexp-quote match))
+                               "\\([^\"]*\\\\\"\\)*[^\"]*\")[ )]")
                  search-func 're-search-forward)) ; XXX danger?!?
 
          (cond
@@ -2102,7 +2134,7 @@ score in `gnus-newsgroup-scored' by SCORE."
     ;; Find fuzzy matches.
     (when fuzzies
       ;; Simplify the entire buffer for easy matching.
-      (gnus-simplify-buffer-fuzzy)
+      (gnus-simplify-buffer-fuzzy gnus-simplify-subject-fuzzy-regexp)
       (while (setq kill (cadaar fuzzies))
        (let* ((match (nth 0 kill))
               (type (nth 3 kill))
@@ -2188,23 +2220,19 @@ score in `gnus-newsgroup-scored' by SCORE."
 (defun gnus-enter-score-words-into-hashtb (hashtb)
   ;; Find all the words in the buffer and enter them into
   ;; the hashtable.
-  (let ((syntab (syntax-table))
-       word val)
+  (let (word val)
     (goto-char (point-min))
-    (unwind-protect
-       (progn
-         (set-syntax-table gnus-adaptive-word-syntax-table)
-         (while (re-search-forward "\\b\\w+\\b" nil t)
-           (setq val
-                 (gnus-gethash
-                  (setq word (downcase (buffer-substring
-                                        (match-beginning 0) (match-end 0))))
-                  hashtb))
-           (gnus-sethash
-            word
-            (append (get-text-property (point-at-eol) 'articles) val)
-            hashtb)))
-      (set-syntax-table syntab))
+    (with-syntax-table gnus-adaptive-word-syntax-table
+      (while (re-search-forward "\\b\\w+\\b" nil t)
+       (setq val
+             (gnus-gethash
+              (setq word (downcase (buffer-substring
+                                    (match-beginning 0) (match-end 0))))
+              hashtb))
+       (gnus-sethash
+        word
+        (append (get-text-property (point-at-eol) 'articles) val)
+        hashtb)))
     ;; Make all the ignorable words ignored.
     (let ((ignored (append gnus-ignored-adaptive-words
                           (if gnus-adaptive-word-no-group-words
@@ -2231,8 +2259,7 @@ score in `gnus-newsgroup-scored' by SCORE."
   "Create adaptive score rules for this newsgroup."
   (when gnus-newsgroup-adaptive
     ;; We change the score file to the adaptive score file.
-    (save-excursion
-      (set-buffer gnus-summary-buffer)
+    (with-current-buffer gnus-summary-buffer
       (gnus-score-load-file
        (or gnus-newsgroup-adaptive-score-file
           (gnus-home-score-file gnus-newsgroup-name t)
@@ -2307,39 +2334,35 @@ score in `gnus-newsgroup-scored' by SCORE."
        (let* ((hashtb (gnus-make-hashtable 1000))
               (date (date-to-day (current-time-string)))
               (data gnus-newsgroup-data)
-              (syntab (syntax-table))
               word d score val)
-         (unwind-protect
-             (progn
-               (set-syntax-table gnus-adaptive-word-syntax-table)
-               ;; Go through all articles.
-               (while (setq d (pop data))
-                 (when (and
-                        (not (gnus-data-pseudo-p d))
-                        (setq score
-                              (cdr (assq
-                                    (gnus-data-mark d)
-                                    gnus-adaptive-word-score-alist))))
-                   ;; This article has a mark that should lead to
-                   ;; adaptive word rules, so we insert the subject
-                   ;; and find all words in that string.
-                   (insert (mail-header-subject (gnus-data-header d)))
-                   (downcase-region (point-min) (point-max))
-                   (goto-char (point-min))
-                   (while (re-search-forward "\\b\\w+\\b" nil t)
-                     ;; Put the word and score into the hashtb.
-                     (setq val (gnus-gethash (setq word (match-string 0))
-                                             hashtb))
-                     (when (or (not gnus-adaptive-word-length-limit)
-                               (> (length word)
-                                  gnus-adaptive-word-length-limit))
-                       (setq val (+ score (or val 0)))
-                       (if (and gnus-adaptive-word-minimum
-                                (< val gnus-adaptive-word-minimum))
-                           (setq val gnus-adaptive-word-minimum))
-                       (gnus-sethash word val hashtb)))
-                   (erase-buffer))))
-           (set-syntax-table syntab))
+         (with-syntax-table gnus-adaptive-word-syntax-table
+           ;; Go through all articles.
+           (while (setq d (pop data))
+             (when (and
+                    (not (gnus-data-pseudo-p d))
+                    (setq score
+                          (cdr (assq
+                                (gnus-data-mark d)
+                                gnus-adaptive-word-score-alist))))
+               ;; This article has a mark that should lead to
+               ;; adaptive word rules, so we insert the subject
+               ;; and find all words in that string.
+               (insert (mail-header-subject (gnus-data-header d)))
+               (downcase-region (point-min) (point-max))
+               (goto-char (point-min))
+               (while (re-search-forward "\\b\\w+\\b" nil t)
+                 ;; Put the word and score into the hashtb.
+                 (setq val (gnus-gethash (setq word (match-string 0))
+                                         hashtb))
+                 (when (or (not gnus-adaptive-word-length-limit)
+                           (> (length word)
+                              gnus-adaptive-word-length-limit))
+                   (setq val (+ score (or val 0)))
+                   (if (and gnus-adaptive-word-minimum
+                            (< val gnus-adaptive-word-minimum))
+                       (setq val gnus-adaptive-word-minimum))
+                   (gnus-sethash word val hashtb)))
+               (erase-buffer))))
          ;; Make all the ignorable words ignored.
          (let ((ignored (append gnus-ignored-adaptive-words
                                 (if gnus-adaptive-word-no-group-words
@@ -2367,7 +2390,8 @@ score in `gnus-newsgroup-scored' by SCORE."
     (when winconf
       (set-window-configuration winconf))
     (gnus-score-remove-from-cache bufnam)
-    (gnus-score-load-file bufnam)))
+    (gnus-score-load-file bufnam)
+    (run-hooks 'gnus-score-edit-done-hook)))
 
 (defun gnus-score-find-trace ()
   "Find all score rules that applies to the current article."
@@ -2395,6 +2419,11 @@ score in `gnus-newsgroup-scored' by SCORE."
                         (interactive)
                         (bury-buffer nil)
                         (gnus-summary-expand-window)))
+       (local-set-key "k"
+                      (lambda ()
+                        (interactive)
+                        (kill-buffer (current-buffer))
+                        (gnus-summary-expand-window)))
        (local-set-key "e" (lambda ()
                             "Run `gnus-score-edit-file-at-point'."
                             (interactive)
@@ -2417,13 +2446,20 @@ score in `gnus-newsgroup-scored' by SCORE."
                   ;; .ADAPT directly:
                   (file-name-nondirectory file)
                   (abbreviate-file-name file))))
+       (insert
+        (format "\nTotal score: %d"
+                (apply '+ (mapcar
+                           (lambda (s)
+                             (or (caddr s)
+                                 gnus-score-interactive-default-score))
+                           trace))))
        (insert
         "\n\nQuick help:
 
 Type `e' to edit score file corresponding to the score rule on current line,
 `f' to format (pretty print) the score file and edit it,
 `t' toggle to truncate long lines in this buffer,
-`q' to quit.
+`q' to quit, `k' to kill score trace buffer.
 
 The first sexp on each line is the score rule, followed by the file name of
 the score file and its full name, including the directory.")
@@ -2637,8 +2673,7 @@ GROUP using BNews sys file syntax."
         (trans (cdr (assq ?: nnheader-file-name-translation-alist)))
         (group-trans (nnheader-translate-file-chars group t))
         ofiles not-match regexp)
-    (save-excursion
-      (set-buffer (gnus-get-buffer-create "*gnus score files*"))
+    (with-current-buffer (gnus-get-buffer-create "*gnus score files*")
       (buffer-disable-undo)
       ;; Go through all score file names and create regexp with them
       ;; as the source.
@@ -2769,9 +2804,7 @@ Destroys the current buffer."
            (lambda (file)
              (cons (inline (gnus-score-file-rank file)) file))
            files)))
-      (mapcar
-       (lambda (f) (cdr f))
-       (sort alist 'car-less-than-car)))))
+      (mapcar 'cdr (sort alist 'car-less-than-car)))))
 
 (defun gnus-score-find-alist (group)
   "Return list of score files for GROUP.
@@ -2784,8 +2817,7 @@ The list is determined from the variable `gnus-score-file-alist'."
       ;; handle the multiple match alist
       (while alist
        (when (string-match (caar alist) group)
-         (setq score-files
-               (nconc score-files (copy-sequence (cdar alist)))))
+         (setq score-files (append (cdar alist) score-files)))
        (setq alist (cdr alist)))
       (setq alist gnus-score-file-single-match-alist)
       ;; handle the single match alist
@@ -2795,8 +2827,7 @@ The list is determined from the variable `gnus-score-file-alist'."
          ;; and score-files is still nil.  -sj
          ;; this can be construed as a "stop searching here" feature :>
          ;; and used to simplify regexps in the single-alist
-         (setq score-files
-               (nconc score-files (copy-sequence (cdar alist))))
+         (setq score-files (append (cdar alist) score-files))
          (setq alist nil))
        (setq alist (cdr alist)))
       ;; cache the score files
@@ -2816,7 +2847,7 @@ The list is determined from the variable `gnus-score-file-alist'."
       (when gnus-score-use-all-scores
        ;; Get the initial score files for this group.
        (when funcs
-         (setq score-files (nreverse (gnus-score-find-alist group))))
+         (setq score-files (copy-sequence (gnus-score-find-alist group))))
        ;; Add any home adapt files.
        (let ((home (gnus-home-score-file group t)))
          (when home
@@ -2963,7 +2994,7 @@ If ADAPT, return the home adaptive file instead."
 
 (defun gnus-current-home-score-file (group)
   "Return the \"current\" regular score file."
-  (car (nreverse (gnus-score-find-alist group))))
+  (car (gnus-score-find-alist group)))
 
 ;;;
 ;;; Score decays
@@ -2978,7 +3009,7 @@ If ADAPT, return the home adaptive file instead."
                           (* (abs score)
                              gnus-score-decay-scale)))))))
     (if (and (featurep 'xemacs)
-            ;; XEmacs' floor can handle only the floating point
+            ;; XEmacs's floor can handle only the floating point
             ;; number below the half of the maximum integer.
             (> (abs n) (lsh -1 -2)))
        (string-to-number
@@ -3006,62 +3037,6 @@ If ADAPT, return the home adaptive file instead."
     ;; Return whether this score file needs to be saved.  By Je-haysuss!
     updated))
 
-(defun gnus-score-regexp-bad-p (regexp)
-  "Test whether REGEXP is safe for Gnus scoring.
-A regexp is unsafe if it matches newline or a buffer boundary.
-
-If the regexp is good, return nil.  If the regexp is bad, return a
-cons cell (SYM . STRING), where the symbol SYM is `new' or `bad'.
-In the `new' case, the string is a safe replacement for REGEXP.
-In the `bad' case, the string is a unsafe subexpression of REGEXP,
-and we do not have a simple replacement to suggest.
-
-See Info node `(gnus)Scoring Tips' for examples of good regular expressions."
-  (let (case-fold-search)
-    (and
-     ;; First, try a relatively fast necessary condition.
-     ;; Notice ranges (like [^:] or [\t-\r]), \s>, \Sw, \W, \', \`:
-     (string-match "\n\\|\\\\[SsW`']\\|\\[\\^\\|[\0-\n]-" regexp)
-     ;; Now break the regexp into tokens, and check each:
-     (let ((tail regexp)               ; remaining regexp to check
-          tok                          ; current token
-          bad                          ; nil, or bad subexpression
-          new                          ; nil, or replacement regexp so far
-          end)                         ; length of current token
-       (while (and (not bad)
-                  (string-match
-                   "\\`\\(\\\\[sS]?.\\|\\[\\^?]?[^]]*]\\|[^\\]\\)"
-                   tail))
-        (setq end (match-end 0)
-              tok (substring tail 0 end)
-              tail (substring tail end))
-        (if;; Is token `bad' (matching newline or buffer ends)?
-            (or (member tok '("\n" "\\W" "\\`" "\\'"))
-                ;; This next handles "[...]", "\\s.", and "\\S.":
-                (and (> end 2) (string-match tok "\n")))
-            (let ((newtok
-                   ;; Try to suggest a replacement for tok ...
-                   (cond ((string-equal tok "\\`") "^") ; or "\\(^\\)"
-                         ((string-equal tok "\\'") "$") ; or "\\($\\)"
-                         ((string-match "\\[\\^" tok) ; very common
-                          (concat (substring tok 0 -1) "\n]")))))
-              (if newtok
-                  (setq new
-                        (concat
-                         (or new
-                             ;; good prefix so far:
-                             (substring regexp 0 (- (+ (length tail) end))))
-                         newtok))
-                ;; No replacement idea, so give up:
-                (setq bad tok)))
-          ;; tok is good, may need to extend new
-          (and new (setq new (concat new tok)))))
-       ;; Now return a value:
-       (cond
-       (bad (cons 'bad bad))
-       (new (cons 'new new))
-       (t nil))))))
-
 (provide 'gnus-score)
 
 ;;; gnus-score.el ends here