*** empty log message ***
[gnus] / lisp / gnus-score.el
index be60027..5128361 100644 (file)
@@ -1,5 +1,5 @@
-1;;; gnus-score.el --- scoring code for Gnus
-;; Copyright (C) 1995,96,97 Free Software Foundation, Inc.
+;;; gnus-score.el --- scoring code for Gnus
+;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk>
 ;;     Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
@@ -34,7 +34,7 @@
 (require 'message)
 
 (defcustom gnus-global-score-files nil
-  "List of global score files and directories.
+  "*List of global score files and directories.
 Set this variable if you want to use people's score files.  One entry
 for each score file or each score file directory.  Gnus will decide
 by itself what score files are applicable to which group.
@@ -50,7 +50,7 @@ score files in the \"/ftp.some-where:/pub/score\" directory.
   :type '(repeat file))
 
 (defcustom gnus-score-file-single-match-alist nil
-  "Alist mapping regexps to lists of score files.
+  "*Alist mapping regexps to lists of score files.
 Each element of this alist should be of the form
        (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
 
@@ -65,7 +65,7 @@ gnus-score-find-score-files-function (which see)."
   :type '(repeat (cons regexp (repeat file))))
 
 (defcustom gnus-score-file-multiple-match-alist nil
-  "Alist mapping regexps to lists of score files.
+  "*Alist mapping regexps to lists of score files.
 Each element of this alist should be of the form
        (\"REGEXP\" [ \"SCORE-FILE-1\" ] [ \"SCORE-FILE-2\" ] ... )
 
@@ -81,18 +81,18 @@ gnus-score-find-score-files-function (which see)."
   :type '(repeat (cons regexp (repeat file))))
 
 (defcustom gnus-score-file-suffix "SCORE"
-  "Suffix of the score files."
+  "*Suffix of the score files."
   :group 'gnus-score-files
   :type 'string)
 
 (defcustom gnus-adaptive-file-suffix "ADAPT"
-  "Suffix of the adaptive score files."
+  "*Suffix of the adaptive score files."
   :group 'gnus-score-files
   :group 'gnus-score-adapt
   :type 'string)
 
 (defcustom gnus-score-find-score-files-function 'gnus-score-find-bnews
-  "Function used to find score files.
+  "*Function used to find score files.
 The function will be called with the group name as the argument, and
 should return a list of score files to apply to that group.  The score
 files do not actually have to exist.
@@ -162,7 +162,7 @@ It is called with one parameter -- the score to be decayed."
   :type 'number)
 
 (defcustom gnus-home-score-file nil
-  "Variable to control where interactive score entries are to go.
+  "*Variable to control where interactive score entries are to go.
 It can be:
 
  * A string
@@ -195,19 +195,19 @@ It can be:
   :type '(choice string
                 (repeat (choice string
                                 (cons regexp (repeat file))
-                                function))
-                function))
+                                (function :value fun)))
+                (function :value fun)))
 
 (defcustom gnus-home-adapt-file nil
-  "Variable to control where new adaptive score entries are to go.
+  "*Variable to control where new adaptive score entries are to go.
 This variable allows the same syntax as `gnus-home-score-file'."
   :group 'gnus-score-adapt
   :group 'gnus-score-files
   :type '(choice string
                 (repeat (choice string
                                 (cons regexp (repeat file))
-                                function))
-                function))
+                                (function :value fun)))
+                (function :value fun)))
 
 (defcustom gnus-default-adaptive-score-alist
   '((gnus-kill-file-mark)
@@ -216,7 +216,7 @@ This variable allows the same syntax as `gnus-home-score-file'."
     (gnus-catchup-mark (subject -10))
     (gnus-killed-mark (from -1) (subject -20))
     (gnus-del-mark (from -2) (subject -15)))
-"Alist of marks and scores."
+"*Alist of marks and scores."
 :group 'gnus-score-adapt
 :type '(repeat (cons (symbol :tag "Mark")
                     (repeat (list (choice :tag "Header"
@@ -226,7 +226,7 @@ This variable allows the same syntax as `gnus-home-score-file'."
                                   (integer :tag "Score"))))))
 
 (defcustom gnus-ignored-adaptive-words nil
-  "List of words to be ignored when doing adaptive word scoring."
+  "*List of words to be ignored when doing adaptive word scoring."
   :group 'gnus-score-adapt
   :type '(repeat string))
 
@@ -245,7 +245,7 @@ This variable allows the same syntax as `gnus-home-score-file'."
     "being" "current" "back" "still" "go" "point" "value" "each" "did"
     "both" "true" "off" "say" "another" "state" "might" "under" "start"
     "try" "re")
-  "Default list of words to be ignored when doing adaptive word scoring."
+  "*Default list of words to be ignored when doing adaptive word scoring."
   :group 'gnus-score-adapt
   :type '(repeat string))
 
@@ -254,11 +254,16 @@ This variable allows the same syntax as `gnus-home-score-file'."
     (,gnus-catchup-mark . -10)
     (,gnus-killed-mark . -20)
     (,gnus-del-mark . -15))
-"Alist of marks and scores."
+"*Alist of marks and scores."
 :group 'gnus-score-adapt
 :type '(repeat (cons (character :tag "Mark")
                     (integer :tag "Score"))))
 
+(defcustom gnus-adaptive-word-minimum nil
+  "*If a number, this is the minimum score value that can be assigned to a word."
+  :group 'gnus-score-adapt
+  :type '(choice (const nil) integer))
+
 (defcustom gnus-score-mimic-keymap nil
   "*Have the score entry functions pretend that they are a keymap."
   :group 'gnus-score-default
@@ -276,13 +281,13 @@ If this variable is nil, exact matching will always be used."
   :type '(choice (const nil) integer))
 
 (defcustom gnus-score-uncacheable-files "ADAPT$"
-  "All score files that match this regexp will not be cached."
+  "*All score files that match this regexp will not be cached."
   :group 'gnus-score-adapt
   :group 'gnus-score-files
   :type 'regexp)
 
 (defcustom gnus-score-default-header nil
-  "Default header when entering new scores.
+  "*Default header when entering new scores.
 
 Should be one of the following symbols.
 
@@ -312,7 +317,7 @@ If nil, the user will be asked for a header."
                 (const :tag "ask" nil)))
 
 (defcustom gnus-score-default-type nil
-  "Default match type when entering new scores.
+  "*Default match type when entering new scores.
 
 Should be one of the following symbols.
 
@@ -342,12 +347,12 @@ 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."
+  "*Use case folding for new score file entries iff not nil."
   :group 'gnus-score-default
   :type 'boolean)
 
 (defcustom gnus-score-default-duration nil
-  "Default duration of effect when entering new scores.
+  "*Default duration of effect when entering new scores.
 
 Should be one of the following symbols.
 
@@ -363,10 +368,15 @@ If nil, the user will be asked for a duration."
                 (const :tag "ask" nil)))
 
 (defcustom gnus-score-after-write-file-function nil
-  "Function called with the name of the score file just written to disk."
+  "*Function called with the name of the score file just written to disk."
   :group 'gnus-score-files
   :type 'function)
 
+(defcustom gnus-score-thread-simplify nil
+  "*If non-nil, subjects will simplified as in threading."
+  :group 'gnus-score-various
+  :type 'boolean) 
+
 \f
 
 ;; Internal variables.
@@ -1008,19 +1018,21 @@ SCORE is the score to add."
 (defun gnus-score-edit-current-scores (file)
   "Edit the current score alist."
   (interactive (list gnus-current-score-file))
-  (let ((winconf (current-window-configuration)))
-    (when (buffer-name gnus-summary-buffer)
-      (gnus-score-save))
-    (gnus-make-directory (file-name-directory file))
-    (setq gnus-score-edit-buffer (find-file-noselect file))
-    (gnus-configure-windows 'edit-score)
-    (gnus-score-mode)
-    (setq gnus-score-edit-exit-function 'gnus-score-edit-done)
-    (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")))
+  (if (not gnus-current-score-file)
+      (error "No current score file")
+    (let ((winconf (current-window-configuration)))
+      (when (buffer-name gnus-summary-buffer)
+       (gnus-score-save))
+      (gnus-make-directory (file-name-directory file))
+      (setq gnus-score-edit-buffer (find-file-noselect file))
+      (gnus-configure-windows 'edit-score)
+      (gnus-score-mode)
+      (setq gnus-score-edit-exit-function 'gnus-score-edit-done)
+      (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"))))
 
 (defun gnus-score-edit-file (file)
   "Edit a score file."
@@ -1096,6 +1108,7 @@ SCORE is the score to add."
          (eval (car (gnus-score-get 'eval alist))))
       ;; Perform possible decays.
       (when (and gnus-decay-scores
+                (or cached (file-exists-p file))
                 (or (not decay)
                     (gnus-decay-scores alist decay)))
        (gnus-score-set 'touched '(t) alist)
@@ -1113,10 +1126,14 @@ SCORE is the score to add."
       ;; We then expand any exclude-file directives.
       (setq gnus-scores-exclude-files
            (nconc
-            (mapcar
-             (lambda (sfile)
-               (expand-file-name sfile (file-name-directory file)))
-             exclude-files)
+            (apply
+             'nconc
+             (mapcar
+              (lambda (sfile)
+                (list
+                 (expand-file-name sfile (file-name-directory file))
+                 (expand-file-name sfile gnus-kill-files-directory)))
+              exclude-files))
             gnus-scores-exclude-files))
       (unless local
        (save-excursion
@@ -1820,6 +1837,8 @@ SCORE is the score to add."
   ;; Insert the unique article headers in the buffer.
   (let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
        ;; gnus-score-index is used as a free variable.
+        (simplify (and gnus-score-thread-simplify
+                       (string= "subject" header)))
        alike last this art entries alist articles
        fuzzies arts words kill)
 
@@ -1835,6 +1854,8 @@ SCORE is the score to add."
     (erase-buffer)
     (while (setq art (pop articles))
       (setq this (aref (car art) gnus-score-index))
+      (if simplify
+        (setq this (gnus-map-function gnus-simplify-subject-functions this)))
       (if (equal last this)
          ;; O(N*H) cons-cells used here, where H is the number of
          ;; headers.
@@ -1860,7 +1881,6 @@ SCORE is the score to add."
            entries (assoc header alist))
       (while (cdr entries)             ;First entry is the header index.
        (let* ((kill (cadr entries))
-              (match (nth 0 kill))
               (type (or (nth 3 kill) 's))
               (score (or (nth 1 kill) gnus-score-interactive-default-score))
               (date (nth 2 kill))
@@ -1868,6 +1888,12 @@ SCORE is the score to add."
               (mt (aref (symbol-name type) 0))
               (case-fold-search (not (memq mt '(?R ?S ?E ?F))))
               (dmt (downcase mt))
+               ; Assume user already simplified regexp and fuzzies
+              (match (if (and simplify (not (memq dmt '(?f ?r))))
+                          (gnus-map-function
+                           gnus-simplify-subject-functions
+                           (nth 0 kill))
+                        (nth 0 kill)))
               (search-func
                (cond ((= dmt ?r) 're-search-forward)
                      ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
@@ -2167,7 +2193,11 @@ SCORE is the score to add."
                      ;; Put the word and score into the hashtb.
                      (setq val (gnus-gethash (setq word (match-string 0))
                                              hashtb))
-                     (gnus-sethash word (+ (or val 0) score) hashtb))
+                     (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))
          ;; Make all the ignorable words ignored.