Import Gnus v5.10.3.
[elisp/gnus.git-] / lisp / gnus-score.el
index 909d39c..3bd29b5 100644 (file)
@@ -1,5 +1,5 @@
 ;;; gnus-score.el --- scoring code for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk>
@@ -36,6 +36,8 @@
 (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
@@ -236,7 +238,8 @@ 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."
   :group 'gnus-score-adapt
-  :type 'integer)
+  :type '(radio (const :format "Unlimited " nil)
+               (integer :format "Maximum length: %v\n" :size 0)))
 
 (defcustom gnus-ignored-adaptive-words nil
   "List of words to be ignored when doing adaptive word scoring."
@@ -489,7 +492,8 @@ of the last successful match.")
   "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."
+used as score.  A symbolic prefix of `a' 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))
 
@@ -503,7 +507,8 @@ used as score."
   "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."
+used as score.  A symbolic prefix of `a' 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))
@@ -872,7 +877,7 @@ If optional argument `EXTRA' is non-nil, it's a non-standard overview header."
     ;; Return the new scoring rule.
     new))
 
-(defun gnus-summary-score-effect (header match type score extra)
+(defun gnus-summary-score-effect (header match type score &optional extra)
   "Simulate the effect of a score file entry.
 HEADER is the header being scored.
 MATCH is the string we are looking for.
@@ -884,8 +889,8 @@ EXTRA is the possible non-standard header."
                                      (lambda (x) (fboundp (nth 2 x)))
                                      t)
                     (read-string "Match: ")
-                    (y-or-n-p "Use regexp match? ")
-                    (prefix-numeric-value current-prefix-arg)))
+                    (if (y-or-n-p "Use regexp match? ") 'r 's)
+                    (string-to-int (read-string "Score: "))))
   (save-excursion
     (unless (and (stringp match) (> (length match) 0))
       (error "No match"))
@@ -935,7 +940,6 @@ EXTRA is the possible non-standard header."
 
 ;; All score code written by Per Abrahamsen <abraham@iesd.auc.dk>.
 
-;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
 (defun gnus-score-set-mark-below (score)
   "Automatically mark articles with score below SCORE as read."
   (interactive
@@ -1102,6 +1106,22 @@ EXTRA is the possible non-standard header."
    4 (substitute-command-keys
       "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits")))
 
+(defun gnus-score-edit-file-at-point ()
+  "Edit score file at point.  Useful especially after `V t'."
+  (interactive)
+  (let* ((string (ffap-string-at-point))
+        ;; FIXME: Should be the full `match element', not just string at
+        ;; point.
+        file)
+    (save-excursion
+      (end-of-line)
+      (setq file (ffap-string-at-point)))
+    (gnus-score-edit-file file)
+    (unless (string= string file)
+      (goto-char (point-min))
+      ;; Goto first match
+      (search-forward string nil t))))
+
 (defun gnus-score-load-file (file)
   ;; Load score file FILE.  Returns a list a retrieved score-alists.
   (let* ((file (expand-file-name
@@ -1478,7 +1498,7 @@ EXTRA is the possible non-standard header."
                (with-current-buffer gnus-summary-buffer
                  (setq gnus-newsgroup-scored scored))))
            ;; Remove the buffer.
-           (kill-buffer (current-buffer)))
+           (gnus-kill-buffer (current-buffer)))
 
          ;; Add articles to `gnus-newsgroup-scored'.
          (while gnus-scores-articles
@@ -1503,7 +1523,7 @@ EXTRA is the possible non-standard header."
   "Lower the score on THREAD with SCORE-ADJUST.
 THREAD is expected to contain a list of the form `(PARENT [CHILD1
 CHILD2 ...])' where PARENT is a header array and each CHILD is a list
-of the same form as THREAD.  The empty list `nil' is valid.  For each
+of the same form as THREAD.  The empty list nil is valid.  For each
 article in the tree, the score of the corresponding entry in
 `gnus-newsgroup-scored' is adjusted by SCORE-ADJUST."
   (while thread
@@ -1724,7 +1744,8 @@ score in `gnus-newsgroup-scored' by SCORE."
                        (setq found t)
                        (when trace
                          (push
-                          (cons (car-safe (rassq alist gnus-score-cache)) kill)
+                          (cons (car-safe (rassq alist gnus-score-cache))
+                                kill)
                           gnus-score-trace)))
                      ;; Update expire date
                      (unless trace
@@ -1811,7 +1832,7 @@ score in `gnus-newsgroup-scored' by SCORE."
            (goto-char (point-min))
            (if (= dmt ?e)
                (while (funcall search-func match nil t)
-                 (and (= (progn (beginning-of-line) (point))
+                 (and (= (gnus-point-at-bol)
                          (match-beginning 0))
                       (= (progn (end-of-line) (point))
                          (match-end 0))
@@ -1830,6 +1851,12 @@ score in `gnus-newsgroup-scored' by SCORE."
                (setq found (setq arts (get-text-property (point) 'articles)))
                ;; Found a match, update scores.
                (while (setq art (pop arts))
+                 (setcdr art (+ score (cdr art)))
+                 (when trace
+                   (push (cons
+                          (car-safe (rassq alist gnus-score-cache))
+                          kill)
+                         gnus-score-trace))
                  (when (setq new (gnus-score-add-followups
                                   (car art) score all-scores thread))
                    (push new news)))))
@@ -1903,7 +1930,7 @@ score in `gnus-newsgroup-scored' by SCORE."
       ;; with working on them as a group.  What a hassle.
       ;; Just wait 'til you see what horrors we commit against `match'...
       (if (= gnus-score-index 9)
-         (setq this (prin1-to-string this))) ; ick.
+         (setq this (gnus-prin1-to-string this))) ; ick.
 
       (if simplify
          (setq this (gnus-map-function gnus-simplify-subject-functions this)))
@@ -2337,6 +2364,13 @@ score in `gnus-newsgroup-scored' by SCORE."
           1 "No score rules apply to the current article (default score %d)."
           gnus-summary-default-score)
        (set-buffer "*Score Trace*")
+       ;; ToDo: Use a keymap instead?
+       (local-set-key "q"
+                      (lambda ()
+                        (interactive)
+                        (bury-buffer nil)
+                        (gnus-summary-expand-window)))
+       (local-set-key "e" 'gnus-score-edit-file-at-point)
        (setq truncate-lines t)
        (while trace
          (insert (format "%S  ->  %s\n" (cdar trace)
@@ -2613,7 +2647,7 @@ GROUP using BNews sys file syntax."
                         (ignore-errors (string-match regexp group-trans))))
            (push (car sfiles) ofiles)))
        (setq sfiles (cdr sfiles)))
-      (kill-buffer (current-buffer))
+      (gnus-kill-buffer (current-buffer))
       ;; Slight kludge here - the last score file returned should be
       ;; the local score file, whether it exists or not.  This is so
       ;; that any score commands the user enters will go to the right
@@ -2745,7 +2779,7 @@ The list is determined from the variable `gnus-score-file-alist'."
       ;; Go through all the functions for finding score files (or actual
       ;; scores) and add them to a list.
       (while funcs
-       (when (gnus-functionp (car funcs))
+       (when (functionp (car funcs))
          (setq score-files
                (append score-files
                        (nreverse (funcall (car funcs) group)))))
@@ -2848,7 +2882,7 @@ If ADAPT, return the home adaptive file instead."
             ((stringp elem)
              elem)
             ;; Function.
-            ((gnus-functionp elem)
+            ((functionp elem)
              (funcall elem group))
             ;; Regexp-file cons.
             ((consp elem)
@@ -2886,13 +2920,19 @@ If ADAPT, return the home adaptive file instead."
 
 (defun gnus-decay-score (score)
   "Decay SCORE according to `gnus-score-decay-constant' and `gnus-score-decay-scale'."
-  (floor
-   (- score
-      (* (if (< score 0) -1 1)
-        (min (abs score)
-             (max gnus-score-decay-constant
-                  (* (abs score)
-                     gnus-score-decay-scale)))))))
+  (let ((n (- score
+             (* (if (< score 0) -1 1)
+                (min (abs score)
+                     (max gnus-score-decay-constant
+                          (* (abs score)
+                             gnus-score-decay-scale)))))))
+    (if (and (featurep 'xemacs)
+            ;; XEmacs' floor can handle only the floating point
+            ;; number below the half of the maximum integer.
+            (> (abs n) (lsh -1 -2)))
+       (string-to-number
+        (car (split-string (number-to-string n) "\\.")))
+      (floor n))))
 
 (defun gnus-decay-scores (alist day)
   "Decay non-permanent scores in ALIST."
@@ -2925,7 +2965,7 @@ 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 `(Gnus)Scoring Tips' for examples of good regular expressions."
+See Info node `(gnus)Scoring Tips' for examples of good regular expressions."
   (let (case-fold-search)
     (and
      ;; First, try a relatively fast necessary condition.