Mercurial > emacs
comparison lisp/gnus/gnus-score.el @ 88155:d7ddb3e565de
sync with trunk
author | Henrik Enberg <henrik.enberg@telia.com> |
---|---|
date | Mon, 16 Jan 2006 00:03:54 +0000 |
parents | 933ab100fb4a |
children |
comparison
equal
deleted
inserted
replaced
88154:8ce476d3ba36 | 88155:d7ddb3e565de |
---|---|
1 ;;; gnus-score.el --- scoring code for Gnus | 1 ;;; gnus-score.el --- scoring code for Gnus |
2 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 | 2 |
3 ;; Free Software Foundation, Inc. | 3 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, |
4 ;; 2004, 2005 Free Software Foundation, Inc. | |
4 | 5 |
5 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk> | 6 ;; Author: Per Abrahamsen <amanda@iesd.auc.dk> |
6 ;; Lars Magne Ingebrigtsen <larsi@gnus.org> | 7 ;; Lars Magne Ingebrigtsen <larsi@gnus.org> |
7 ;; Keywords: news | 8 ;; Keywords: news |
8 | 9 |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 ;; GNU General Public License for more details. | 20 ;; GNU General Public License for more details. |
20 | 21 |
21 ;; You should have received a copy of the GNU General Public License | 22 ;; You should have received a copy of the GNU General Public License |
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the | 23 ;; along with GNU Emacs; see the file COPYING. If not, write to the |
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
24 ;; Boston, MA 02111-1307, USA. | 25 ;; Boston, MA 02110-1301, USA. |
25 | 26 |
26 ;;; Commentary: | 27 ;;; Commentary: |
27 | 28 |
28 ;;; Code: | 29 ;;; Code: |
29 | 30 |
30 (eval-when-compile (require 'cl)) | 31 (eval-when-compile (require 'cl)) |
31 | 32 |
32 (require 'gnus) | 33 (require 'gnus) |
33 (require 'gnus-sum) | 34 (require 'gnus-sum) |
34 (require 'gnus-range) | 35 (require 'gnus-range) |
36 (require 'gnus-win) | |
35 (require 'message) | 37 (require 'message) |
36 (require 'score-mode) | 38 (require 'score-mode) |
39 | |
40 (autoload 'ffap-string-at-point "ffap") | |
37 | 41 |
38 (defcustom gnus-global-score-files nil | 42 (defcustom gnus-global-score-files nil |
39 "List of global score files and directories. | 43 "List of global score files and directories. |
40 Set this variable if you want to use people's score files. One entry | 44 Set this variable if you want to use people's score files. One entry |
41 for each score file or each score file directory. Gnus will decide | 45 for each score file or each score file directory. Gnus will decide |
45 \"/ftp.gnus.org@ftp:/pub/larsi/ding/score/soc.motss.SCORE\" and all | 49 \"/ftp.gnus.org@ftp:/pub/larsi/ding/score/soc.motss.SCORE\" and all |
46 score files in the \"/ftp.some-where:/pub/score\" directory. | 50 score files in the \"/ftp.some-where:/pub/score\" directory. |
47 | 51 |
48 (setq gnus-global-score-files | 52 (setq gnus-global-score-files |
49 '(\"/ftp.gnus.org:/pub/larsi/ding/score/soc.motss.SCORE\" | 53 '(\"/ftp.gnus.org:/pub/larsi/ding/score/soc.motss.SCORE\" |
50 \"/ftp.some-where:/pub/score\"))" | 54 \"/ftp.some-where:/pub/score\"))" |
51 :group 'gnus-score-files | 55 :group 'gnus-score-files |
52 :type '(repeat file)) | 56 :type '(repeat file)) |
53 | 57 |
54 (defcustom gnus-score-file-single-match-alist nil | 58 (defcustom gnus-score-file-single-match-alist nil |
55 "Alist mapping regexps to lists of score files. | 59 "Alist mapping regexps to lists of score files. |
136 :group 'gnus-score-expire | 140 :group 'gnus-score-expire |
137 :type '(choice (const :tag "never" nil) | 141 :type '(choice (const :tag "never" nil) |
138 number)) | 142 number)) |
139 | 143 |
140 (defcustom gnus-update-score-entry-dates t | 144 (defcustom gnus-update-score-entry-dates t |
141 "*In non-nil, update matching score entry dates. | 145 "*If non-nil, update matching score entry dates. |
142 If this variable is nil, then score entries that provide matches | 146 If this variable is nil, then score entries that provide matches |
143 will be expired along with non-matching score entries." | 147 will be expired along with non-matching score entries." |
144 :group 'gnus-score-expire | 148 :group 'gnus-score-expire |
145 :type 'boolean) | 149 :type 'boolean) |
146 | 150 |
169 (defcustom gnus-home-score-file nil | 173 (defcustom gnus-home-score-file nil |
170 "Variable to control where interactive score entries are to go. | 174 "Variable to control where interactive score entries are to go. |
171 It can be: | 175 It can be: |
172 | 176 |
173 * A string | 177 * A string |
174 This file file will be used as the home score file. | 178 This file will be used as the home score file. |
175 | 179 |
176 * A function | 180 * A function |
177 The result of this function will be used as the home score file. | 181 The result of this function will be used as the home score file. |
178 The function will be passed the name of the group as its | 182 The function will be passed the name of the group as its |
179 parameter. | 183 parameter. |
180 | 184 |
181 * A list | 185 * A list |
182 The elements in this list can be: | 186 The elements in this list can be: |
183 | 187 |
184 * `(regexp file-name ...)' | 188 * `(regexp file-name ...)' |
185 If the `regexp' matches the group name, the first `file-name' will | 189 If the `regexp' matches the group name, the first `file-name' |
186 will be used as the home score file. (Multiple filenames are | 190 will be used as the home score file. (Multiple filenames are |
187 allowed so that one may use gnus-score-file-single-match-alist to | 191 allowed so that one may use gnus-score-file-single-match-alist to |
188 set this variable.) | 192 set this variable.) |
189 | 193 |
190 * A function. | 194 * A function. |
215 (cons regexp (repeat file)) | 219 (cons regexp (repeat file)) |
216 (function :value fun))) | 220 (function :value fun))) |
217 (function :value fun))) | 221 (function :value fun))) |
218 | 222 |
219 (defcustom gnus-default-adaptive-score-alist | 223 (defcustom gnus-default-adaptive-score-alist |
220 '((gnus-kill-file-mark) | 224 `((gnus-kill-file-mark) |
221 (gnus-unread-mark) | 225 (gnus-unread-mark) |
222 (gnus-read-mark (from 3) (subject 30)) | 226 (gnus-read-mark |
223 (gnus-catchup-mark (subject -10)) | 227 (from , (+ 2 gnus-score-decay-constant)) |
224 (gnus-killed-mark (from -1) (subject -20)) | 228 (subject , (+ 27 gnus-score-decay-constant))) |
225 (gnus-del-mark (from -2) (subject -15))) | 229 (gnus-catchup-mark |
226 "*Alist of marks and scores." | 230 (subject , (+ -7 (* -1 gnus-score-decay-constant)))) |
231 (gnus-killed-mark | |
232 (from , (- -1 gnus-score-decay-constant)) | |
233 (subject , (+ -17 (* -1 gnus-score-decay-constant)))) | |
234 (gnus-del-mark | |
235 (from , (- -1 gnus-score-decay-constant)) | |
236 (subject , (+ -12 (* -1 gnus-score-decay-constant))))) | |
237 "Alist of marks and scores. | |
238 If you use score decays, you might want to set values higher than | |
239 `gnus-score-decay-constant'." | |
227 :group 'gnus-score-adapt | 240 :group 'gnus-score-adapt |
228 :type '(repeat (cons (symbol :tag "Mark") | 241 :type '(repeat (cons (symbol :tag "Mark") |
229 (repeat (list (choice :tag "Header" | 242 (repeat (list (choice :tag "Header" |
230 (const from) | 243 (const from) |
231 (const subject) | 244 (const subject) |
232 (symbol :tag "other")) | 245 (symbol :tag "other")) |
233 (integer :tag "Score")))))) | 246 (integer :tag "Score")))))) |
247 | |
248 (defcustom gnus-adaptive-word-length-limit nil | |
249 "*Words of a length lesser than this limit will be ignored when doing adaptive scoring." | |
250 :version "22.1" | |
251 :group 'gnus-score-adapt | |
252 :type '(radio (const :format "Unlimited " nil) | |
253 (integer :format "Maximum length: %v"))) | |
234 | 254 |
235 (defcustom gnus-ignored-adaptive-words nil | 255 (defcustom gnus-ignored-adaptive-words nil |
236 "List of words to be ignored when doing adaptive word scoring." | 256 "List of words to be ignored when doing adaptive word scoring." |
237 :group 'gnus-score-adapt | 257 :group 'gnus-score-adapt |
238 :type '(repeat string)) | 258 :type '(repeat string)) |
481 | 501 |
482 (defun gnus-summary-lower-score (&optional score symp) | 502 (defun gnus-summary-lower-score (&optional score symp) |
483 "Make a score entry based on the current article. | 503 "Make a score entry based on the current article. |
484 The user will be prompted for header to score on, match type, | 504 The user will be prompted for header to score on, match type, |
485 permanence, and the string to be used. The numerical prefix will be | 505 permanence, and the string to be used. The numerical prefix will be |
486 used as score." | 506 used as score. A symbolic prefix of `a' says to use the `all.SCORE' |
507 file for the command instead of the current score file." | |
487 (interactive (gnus-interactive "P\ny")) | 508 (interactive (gnus-interactive "P\ny")) |
488 (gnus-summary-increase-score (- (gnus-score-delta-default score)) symp)) | 509 (gnus-summary-increase-score (- (gnus-score-delta-default score)) symp)) |
489 | 510 |
490 (defun gnus-score-kill-help-buffer () | 511 (defun gnus-score-kill-help-buffer () |
491 (when (get-buffer "*Score Help*") | 512 (when (get-buffer "*Score Help*") |
495 | 516 |
496 (defun gnus-summary-increase-score (&optional score symp) | 517 (defun gnus-summary-increase-score (&optional score symp) |
497 "Make a score entry based on the current article. | 518 "Make a score entry based on the current article. |
498 The user will be prompted for header to score on, match type, | 519 The user will be prompted for header to score on, match type, |
499 permanence, and the string to be used. The numerical prefix will be | 520 permanence, and the string to be used. The numerical prefix will be |
500 used as score." | 521 used as score. A symbolic prefix of `a' says to use the `all.SCORE' |
522 file for the command instead of the current score file." | |
501 (interactive (gnus-interactive "P\ny")) | 523 (interactive (gnus-interactive "P\ny")) |
502 (let* ((nscore (gnus-score-delta-default score)) | 524 (let* ((nscore (gnus-score-delta-default score)) |
503 (prefix (if (< nscore 0) ?L ?I)) | 525 (prefix (if (< nscore 0) ?L ?I)) |
504 (increase (> nscore 0)) | 526 (increase (> nscore 0)) |
505 (char-to-header | 527 (char-to-header |
614 (when (or (= pchar ??) (= pchar ?\C-h)) | 636 (when (or (= pchar ??) (= pchar ?\C-h)) |
615 (setq pchar nil) | 637 (setq pchar nil) |
616 (gnus-score-insert-help "Match permanence" char-to-perm 2))) | 638 (gnus-score-insert-help "Match permanence" char-to-perm 2))) |
617 | 639 |
618 (gnus-score-kill-help-buffer) | 640 (gnus-score-kill-help-buffer) |
619 (if mimic (message "%c %c %c" prefix hchar tchar pchar) | 641 (if mimic (message "%c %c %c %c" prefix hchar tchar pchar) |
620 (message "")) | 642 (message "")) |
621 (unless (setq temporary (cadr (assq pchar char-to-perm))) | 643 (unless (setq temporary (cadr (assq pchar char-to-perm))) |
622 ;; Deal with der(r)ided superannuated paradigms. | 644 ;; Deal with der(r)ided superannuated paradigms. |
623 (when (and (eq (1+ prefix) 77) | 645 (when (and (eq (1+ prefix) 77) |
624 (eq (+ hchar 12) 109) | 646 (eq (+ hchar 12) 109) |
635 ;; we must find out which header is in question. | 657 ;; we must find out which header is in question. |
636 (setq extra | 658 (setq extra |
637 (and gnus-extra-headers | 659 (and gnus-extra-headers |
638 (equal (nth 1 entry) "extra") | 660 (equal (nth 1 entry) "extra") |
639 (intern ; need symbol | 661 (intern ; need symbol |
640 (gnus-completing-read | 662 (gnus-completing-read-with-default |
641 (symbol-name (car gnus-extra-headers)) ; default response | 663 (symbol-name (car gnus-extra-headers)) ; default response |
642 "Score extra header:" ; prompt | 664 "Score extra header" ; prompt |
643 (mapcar (lambda (x) ; completion list | 665 (mapcar (lambda (x) ; completion list |
644 (cons (symbol-name x) x)) | 666 (cons (symbol-name x) x)) |
645 gnus-extra-headers) | 667 gnus-extra-headers) |
646 nil ; no completion limit | 668 nil ; no completion limit |
647 t)))) ; require match | 669 t)))) ; require match |
727 (setq pad (- width 3)) | 749 (setq pad (- width 3)) |
728 (setq format (concat "%c: %-" (int-to-string pad) "s")) | 750 (setq format (concat "%c: %-" (int-to-string pad) "s")) |
729 (insert (format format (caar alist) (nth idx (car alist)))) | 751 (insert (format format (caar alist) (nth idx (car alist)))) |
730 (setq alist (cdr alist)) | 752 (setq alist (cdr alist)) |
731 (setq i (1+ i)))) | 753 (setq i (1+ i)))) |
754 (goto-char (point-min)) | |
732 ;; display ourselves in a small window at the bottom | 755 ;; display ourselves in a small window at the bottom |
733 (gnus-appt-select-lowest-window) | 756 (gnus-appt-select-lowest-window) |
734 (split-window) | 757 (if (< (/ (window-height) 2) window-min-height) |
735 (pop-to-buffer "*Score Help*") | 758 (switch-to-buffer "*Score Help*") |
759 (split-window) | |
760 (pop-to-buffer "*Score Help*")) | |
736 (let ((window-min-height 1)) | 761 (let ((window-min-height 1)) |
737 (shrink-window-if-larger-than-buffer)) | 762 (shrink-window-if-larger-than-buffer)) |
738 (select-window (get-buffer-window gnus-summary-buffer t)))) | 763 (select-window (gnus-get-buffer-window gnus-summary-buffer t)))) |
739 | 764 |
740 (defun gnus-summary-header (header &optional no-err extra) | 765 (defun gnus-summary-header (header &optional no-err extra) |
741 ;; Return HEADER for current articles, or error. | 766 ;; Return HEADER for current articles, or error. |
742 (let ((article (gnus-summary-article-number)) | 767 (let ((article (gnus-summary-article-number)) |
743 headers) | 768 headers) |
809 match)))) | 834 match)))) |
810 | 835 |
811 ;; If this is an integer comparison, we transform from string to int. | 836 ;; If this is an integer comparison, we transform from string to int. |
812 (if (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer) | 837 (if (eq (nth 2 (assoc header gnus-header-index)) 'gnus-score-integer) |
813 (if (stringp match) | 838 (if (stringp match) |
814 (setq match (string-to-int match))) | 839 (setq match (string-to-number match))) |
815 (set-text-properties 0 (length match) nil match)) | 840 (set-text-properties 0 (length match) nil match)) |
816 | 841 |
817 (unless (eq date 'now) | 842 (unless (eq date 'now) |
818 ;; Add the score entry to the score file. | 843 ;; Add the score entry to the score file. |
819 (when (= score gnus-score-interactive-default-score) | 844 (when (= score gnus-score-interactive-default-score) |
861 (gnus-summary-rescore))) | 886 (gnus-summary-rescore))) |
862 | 887 |
863 ;; Return the new scoring rule. | 888 ;; Return the new scoring rule. |
864 new)) | 889 new)) |
865 | 890 |
866 (defun gnus-summary-score-effect (header match type score extra) | 891 (defun gnus-summary-score-effect (header match type score &optional extra) |
867 "Simulate the effect of a score file entry. | 892 "Simulate the effect of a score file entry. |
868 HEADER is the header being scored. | 893 HEADER is the header being scored. |
869 MATCH is the string we are looking for. | 894 MATCH is the string we are looking for. |
870 TYPE is the score type. | 895 TYPE is the score type. |
871 SCORE is the score to add. | 896 SCORE is the score to add. |
873 (interactive (list (completing-read "Header: " | 898 (interactive (list (completing-read "Header: " |
874 gnus-header-index | 899 gnus-header-index |
875 (lambda (x) (fboundp (nth 2 x))) | 900 (lambda (x) (fboundp (nth 2 x))) |
876 t) | 901 t) |
877 (read-string "Match: ") | 902 (read-string "Match: ") |
878 (y-or-n-p "Use regexp match? ") | 903 (if (y-or-n-p "Use regexp match? ") 'r 's) |
879 (prefix-numeric-value current-prefix-arg))) | 904 (string-to-number (read-string "Score: ")))) |
880 (save-excursion | 905 (save-excursion |
881 (unless (and (stringp match) (> (length match) 0)) | 906 (unless (and (stringp match) (> (length match) 0)) |
882 (error "No match")) | 907 (error "No match")) |
883 (goto-char (point-min)) | 908 (goto-char (point-min)) |
884 (let ((regexp (cond ((eq type 'f) | 909 (let ((regexp (cond ((eq type 'f) |
924 ;;; Gnus Score Files | 949 ;;; Gnus Score Files |
925 ;;; | 950 ;;; |
926 | 951 |
927 ;; All score code written by Per Abrahamsen <abraham@iesd.auc.dk>. | 952 ;; All score code written by Per Abrahamsen <abraham@iesd.auc.dk>. |
928 | 953 |
929 ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>. | |
930 (defun gnus-score-set-mark-below (score) | 954 (defun gnus-score-set-mark-below (score) |
931 "Automatically mark articles with score below SCORE as read." | 955 "Automatically mark articles with score below SCORE as read." |
932 (interactive | 956 (interactive |
933 (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg)) | 957 (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg)) |
934 (string-to-int (read-string "Mark below: "))))) | 958 (string-to-number (read-string "Mark below: "))))) |
935 (setq score (or score gnus-summary-default-score 0)) | 959 (setq score (or score gnus-summary-default-score 0)) |
936 (gnus-score-set 'mark (list score)) | 960 (gnus-score-set 'mark (list score)) |
937 (gnus-score-set 'touched '(t)) | 961 (gnus-score-set 'touched '(t)) |
938 (setq gnus-summary-mark-below score) | 962 (setq gnus-summary-mark-below score) |
939 (gnus-score-update-lines)) | 963 (gnus-score-update-lines)) |
963 | 987 |
964 (defun gnus-score-set-expunge-below (score) | 988 (defun gnus-score-set-expunge-below (score) |
965 "Automatically expunge articles with score below SCORE." | 989 "Automatically expunge articles with score below SCORE." |
966 (interactive | 990 (interactive |
967 (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg)) | 991 (list (or (and current-prefix-arg (prefix-numeric-value current-prefix-arg)) |
968 (string-to-int (read-string "Set expunge below: "))))) | 992 (string-to-number (read-string "Set expunge below: "))))) |
969 (setq score (or score gnus-summary-default-score 0)) | 993 (setq score (or score gnus-summary-default-score 0)) |
970 (gnus-score-set 'expunge (list score)) | 994 (gnus-score-set 'expunge (list score)) |
971 (gnus-score-set 'touched '(t))) | 995 (gnus-score-set 'touched '(t))) |
972 | 996 |
973 (defun gnus-score-followup-article (&optional score) | 997 (defun gnus-score-followup-article (&optional score) |
1090 (make-local-variable 'gnus-prev-winconf) | 1114 (make-local-variable 'gnus-prev-winconf) |
1091 (setq gnus-prev-winconf winconf)) | 1115 (setq gnus-prev-winconf winconf)) |
1092 (gnus-message | 1116 (gnus-message |
1093 4 (substitute-command-keys | 1117 4 (substitute-command-keys |
1094 "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits"))) | 1118 "\\<gnus-score-mode-map>\\[gnus-score-edit-exit] to save edits"))) |
1119 | |
1120 (defun gnus-score-edit-file-at-point (&optional format) | |
1121 "Edit score file at point in Score Trace buffers. | |
1122 If FORMAT, also format the current score file." | |
1123 (let* ((rule (save-excursion | |
1124 (beginning-of-line) | |
1125 (read (current-buffer)))) | |
1126 (sep "[ \n\r\t]*") | |
1127 ;; Must be synced with `gnus-score-find-trace': | |
1128 (reg " -> +") | |
1129 (file (save-excursion | |
1130 (end-of-line) | |
1131 (if (and (re-search-backward reg (gnus-point-at-bol) t) | |
1132 (re-search-forward reg (gnus-point-at-eol) t)) | |
1133 (buffer-substring (point) (gnus-point-at-eol)) | |
1134 nil)))) | |
1135 (if (or (not file) | |
1136 (string-match "\\<\\(non-file rule\\|A file\\)\\>" file) | |
1137 ;; (see `gnus-score-find-trace' and `gnus-score-advanced') | |
1138 (string= "" file)) | |
1139 (gnus-error 3 "Can't find a score file in current line.") | |
1140 (gnus-score-edit-file file) | |
1141 (when format | |
1142 (gnus-score-pretty-print)) | |
1143 (when (consp rule) ;; the rule exists | |
1144 (setq rule (mapconcat #'(lambda (obj) | |
1145 (regexp-quote (format "%S" obj))) | |
1146 rule | |
1147 sep)) | |
1148 (goto-char (point-min)) | |
1149 (re-search-forward rule nil t) | |
1150 ;; make it easy to use `kill-sexp': | |
1151 (goto-char (1- (match-beginning 0))))))) | |
1095 | 1152 |
1096 (defun gnus-score-load-file (file) | 1153 (defun gnus-score-load-file (file) |
1097 ;; Load score file FILE. Returns a list a retrieved score-alists. | 1154 ;; Load score file FILE. Returns a list a retrieved score-alists. |
1098 (let* ((file (expand-file-name | 1155 (let* ((file (expand-file-name |
1099 (or (and (string-match | 1156 (or (and (string-match |
1141 (let ((mark (car (gnus-score-get 'mark alist))) | 1198 (let ((mark (car (gnus-score-get 'mark alist))) |
1142 (expunge (car (gnus-score-get 'expunge alist))) | 1199 (expunge (car (gnus-score-get 'expunge alist))) |
1143 (mark-and-expunge (car (gnus-score-get 'mark-and-expunge alist))) | 1200 (mark-and-expunge (car (gnus-score-get 'mark-and-expunge alist))) |
1144 (files (gnus-score-get 'files alist)) | 1201 (files (gnus-score-get 'files alist)) |
1145 (exclude-files (gnus-score-get 'exclude-files alist)) | 1202 (exclude-files (gnus-score-get 'exclude-files alist)) |
1146 (orphan (car (gnus-score-get 'orphan alist))) | 1203 (orphan (car (gnus-score-get 'orphan alist))) |
1147 (adapt (gnus-score-get 'adapt alist)) | 1204 (adapt (gnus-score-get 'adapt alist)) |
1148 (thread-mark-and-expunge | 1205 (thread-mark-and-expunge |
1149 (car (gnus-score-get 'thread-mark-and-expunge alist))) | 1206 (car (gnus-score-get 'thread-mark-and-expunge alist))) |
1150 (adapt-file (car (gnus-score-get 'adapt-file alist))) | 1207 (adapt-file (car (gnus-score-get 'adapt-file alist))) |
1151 (local (gnus-score-get 'local alist)) | 1208 (local (gnus-score-get 'local alist)) |
1200 (setq gnus-newsgroup-adaptive nil)) | 1257 (setq gnus-newsgroup-adaptive nil)) |
1201 ((consp adapt) | 1258 ((consp adapt) |
1202 (setq gnus-newsgroup-adaptive t) | 1259 (setq gnus-newsgroup-adaptive t) |
1203 adapt) | 1260 adapt) |
1204 (t | 1261 (t |
1205 ;;(setq gnus-newsgroup-adaptive gnus-use-adaptive-scoring) | |
1206 gnus-default-adaptive-score-alist))) | 1262 gnus-default-adaptive-score-alist))) |
1207 (setq gnus-thread-expunge-below | 1263 (setq gnus-thread-expunge-below |
1208 (or thread-mark-and-expunge gnus-thread-expunge-below)) | 1264 (or thread-mark-and-expunge gnus-thread-expunge-below)) |
1209 (setq gnus-summary-mark-below | 1265 (setq gnus-summary-mark-below |
1210 (or mark mark-and-expunge gnus-summary-mark-below)) | 1266 (or mark mark-and-expunge gnus-summary-mark-below)) |
1364 ;; are not meant to be edited by human hands. | 1420 ;; are not meant to be edited by human hands. |
1365 (gnus-prin1 score) | 1421 (gnus-prin1 score) |
1366 ;; This is a normal score file, so we print it very | 1422 ;; This is a normal score file, so we print it very |
1367 ;; prettily. | 1423 ;; prettily. |
1368 (let ((lisp-mode-syntax-table score-mode-syntax-table)) | 1424 (let ((lisp-mode-syntax-table score-mode-syntax-table)) |
1369 (pp score (current-buffer))))) | 1425 (gnus-pp score)))) |
1370 (gnus-make-directory (file-name-directory file)) | 1426 (gnus-make-directory (file-name-directory file)) |
1371 ;; If the score file is empty, we delete it. | 1427 ;; If the score file is empty, we delete it. |
1372 (if (zerop (buffer-size)) | 1428 (if (zerop (buffer-size)) |
1373 (delete-file file) | 1429 (delete-file file) |
1374 ;; There are scores, so we write the file. | 1430 ;; There are scores, so we write the file. |
1426 (expire (and gnus-score-expiry-days | 1482 (expire (and gnus-score-expiry-days |
1427 (- now gnus-score-expiry-days))) | 1483 (- now gnus-score-expiry-days))) |
1428 (headers gnus-newsgroup-headers) | 1484 (headers gnus-newsgroup-headers) |
1429 (current-score-file gnus-current-score-file) | 1485 (current-score-file gnus-current-score-file) |
1430 entry header new) | 1486 entry header new) |
1431 (gnus-message 5 "Scoring...") | 1487 (gnus-message 7 "Scoring...") |
1432 ;; Create articles, an alist of the form `(HEADER . SCORE)'. | 1488 ;; Create articles, an alist of the form `(HEADER . SCORE)'. |
1433 (while (setq header (pop headers)) | 1489 (while (setq header (pop headers)) |
1434 ;; WARNING: The assq makes the function O(N*S) while it could | 1490 ;; WARNING: The assq makes the function O(N*S) while it could |
1435 ;; be written as O(N+S), where N is (length gnus-newsgroup-headers) | 1491 ;; be written as O(N+S), where N is (length gnus-newsgroup-headers) |
1436 ;; and S is (length gnus-newsgroup-scored). | 1492 ;; and S is (length gnus-newsgroup-scored). |
1468 (when (gnus-buffer-live-p gnus-summary-buffer) | 1524 (when (gnus-buffer-live-p gnus-summary-buffer) |
1469 (let ((scored gnus-newsgroup-scored)) | 1525 (let ((scored gnus-newsgroup-scored)) |
1470 (with-current-buffer gnus-summary-buffer | 1526 (with-current-buffer gnus-summary-buffer |
1471 (setq gnus-newsgroup-scored scored)))) | 1527 (setq gnus-newsgroup-scored scored)))) |
1472 ;; Remove the buffer. | 1528 ;; Remove the buffer. |
1473 (kill-buffer (current-buffer))) | 1529 (gnus-kill-buffer (current-buffer))) |
1474 | 1530 |
1475 ;; Add articles to `gnus-newsgroup-scored'. | 1531 ;; Add articles to `gnus-newsgroup-scored'. |
1476 (while gnus-scores-articles | 1532 (while gnus-scores-articles |
1477 (when (or (/= gnus-summary-default-score | 1533 (when (or (/= gnus-summary-default-score |
1478 (cdar gnus-scores-articles)) | 1534 (cdar gnus-scores-articles)) |
1487 (while score | 1543 (while score |
1488 (when (consp (caar score)) | 1544 (when (consp (caar score)) |
1489 (gnus-score-advanced (car score) trace)) | 1545 (gnus-score-advanced (car score) trace)) |
1490 (pop score)))) | 1546 (pop score)))) |
1491 | 1547 |
1492 (gnus-message 5 "Scoring...done")))))) | 1548 (gnus-message 7 "Scoring...done")))))) |
1493 | 1549 |
1494 (defun gnus-score-lower-thread (thread score-adjust) | 1550 (defun gnus-score-lower-thread (thread score-adjust) |
1495 "Lower the score on THREAD with SCORE-ADJUST. | 1551 "Lower the score on THREAD with SCORE-ADJUST. |
1496 THREAD is expected to contain a list of the form `(PARENT [CHILD1 | 1552 THREAD is expected to contain a list of the form `(PARENT [CHILD1 |
1497 CHILD2 ...])' where PARENT is a header array and each CHILD is a list | 1553 CHILD2 ...])' where PARENT is a header array and each CHILD is a list |
1498 of the same form as THREAD. The empty list `nil' is valid. For each | 1554 of the same form as THREAD. The empty list nil is valid. For each |
1499 article in the tree, the score of the corresponding entry in | 1555 article in the tree, the score of the corresponding entry in |
1500 `gnus-newsgroup-scored' is adjusted by SCORE-ADJUST." | 1556 `gnus-newsgroup-scored' is adjusted by SCORE-ADJUST." |
1501 (while thread | 1557 (while thread |
1502 (let ((head (car thread))) | 1558 (let ((head (car thread))) |
1503 (if (listp head) | 1559 (if (listp head) |
1514 "Score orphans. | 1570 "Score orphans. |
1515 A root is an article with no references. An orphan is an article | 1571 A root is an article with no references. An orphan is an article |
1516 which has references, but is not connected via its references to a | 1572 which has references, but is not connected via its references to a |
1517 root article. This function finds all the orphans, and adjusts their | 1573 root article. This function finds all the orphans, and adjusts their |
1518 score in `gnus-newsgroup-scored' by SCORE." | 1574 score in `gnus-newsgroup-scored' by SCORE." |
1519 (let ((threads (gnus-make-threads))) | 1575 ;; gnus-make-threads produces a list, where each entry is a "thread" |
1520 ;; gnus-make-threads produces a list, where each entry is a "thread" | 1576 ;; as described in the gnus-score-lower-thread docs. This function |
1521 ;; as described in the gnus-score-lower-thread docs. This function | 1577 ;; will be called again (after limiting has been done) if the display |
1522 ;; will be called again (after limiting has been done) if the display | 1578 ;; is threaded. It would be nice to somehow save this info and use |
1523 ;; is threaded. It would be nice to somehow save this info and use | 1579 ;; it later. |
1524 ;; it later. | 1580 (dolist (thread (gnus-make-threads)) |
1525 (while threads | 1581 (let ((id (aref (car thread) gnus-score-index))) |
1526 (let* ((thread (car threads)) | 1582 ;; If the parent of the thread is not a root, lower the score of |
1527 (id (aref (car thread) gnus-score-index))) | 1583 ;; it and its descendants. Note that some roots seem to satisfy |
1528 ;; If the parent of the thread is not a root, lower the score of | 1584 ;; (eq id nil) and some (eq id ""); not sure why. |
1529 ;; it and its descendants. Note that some roots seem to satisfy | 1585 (when (and id |
1530 ;; (eq id nil) and some (eq id ""); not sure why. | 1586 (not (string= id ""))) |
1531 (if (and id (not (string= id ""))) | 1587 (gnus-score-lower-thread thread score))))) |
1532 (gnus-score-lower-thread thread score))) | |
1533 (setq threads (cdr threads))))) | |
1534 | 1588 |
1535 (defun gnus-score-integer (scores header now expire &optional trace) | 1589 (defun gnus-score-integer (scores header now expire &optional trace) |
1536 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) | 1590 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) |
1537 entries alist) | 1591 entries alist) |
1538 ;; Find matches. | 1592 ;; Find matches. |
1716 ;; Found a match, update scores. | 1770 ;; Found a match, update scores. |
1717 (setcdr (car articles) (+ score (cdar articles))) | 1771 (setcdr (car articles) (+ score (cdar articles))) |
1718 (setq found t) | 1772 (setq found t) |
1719 (when trace | 1773 (when trace |
1720 (push | 1774 (push |
1721 (cons (car-safe (rassq alist gnus-score-cache)) kill) | 1775 (cons (car-safe (rassq alist gnus-score-cache)) |
1776 kill) | |
1722 gnus-score-trace))) | 1777 gnus-score-trace))) |
1723 ;; Update expire date | 1778 ;; Update expire date |
1724 (unless trace | 1779 (unless trace |
1725 (cond | 1780 (cond |
1726 ((null date)) ;Permanent entry. | 1781 ((null date)) ;Permanent entry. |
1774 (when last | 1829 (when last |
1775 (insert last ?\n) | 1830 (insert last ?\n) |
1776 (put-text-property (1- (point)) (point) 'articles alike)) | 1831 (put-text-property (1- (point)) (point) 'articles alike)) |
1777 (setq alike (list art) | 1832 (setq alike (list art) |
1778 last this))) | 1833 last this))) |
1779 (when last ; Bwadr, duplicate code. | 1834 (when last ; Bwadr, duplicate code. |
1780 (insert last ?\n) | 1835 (insert last ?\n) |
1781 (put-text-property (1- (point)) (point) 'articles alike)) | 1836 (put-text-property (1- (point)) (point) 'articles alike)) |
1782 | 1837 |
1783 ;; Find matches. | 1838 ;; Find matches. |
1784 (while scores | 1839 (while scores |
1785 (setq alist (car scores) | 1840 (setq alist (car scores) |
1786 scores (cdr scores) | 1841 scores (cdr scores) |
1787 entries (assoc header alist)) | 1842 entries (assoc header alist)) |
1788 (while (cdr entries) ;First entry is the header index. | 1843 (while (cdr entries) ;First entry is the header index. |
1789 (let* ((rest (cdr entries)) | 1844 (let* ((rest (cdr entries)) |
1790 (kill (car rest)) | 1845 (kill (car rest)) |
1791 (match (nth 0 kill)) | 1846 (match (nth 0 kill)) |
1792 (type (or (nth 3 kill) 's)) | 1847 (type (or (nth 3 kill) 's)) |
1793 (score (or (nth 1 kill) gnus-score-interactive-default-score)) | 1848 (score (or (nth 1 kill) gnus-score-interactive-default-score)) |
1803 (t (error "Invalid match type: %s" type)))) | 1858 (t (error "Invalid match type: %s" type)))) |
1804 arts art) | 1859 arts art) |
1805 (goto-char (point-min)) | 1860 (goto-char (point-min)) |
1806 (if (= dmt ?e) | 1861 (if (= dmt ?e) |
1807 (while (funcall search-func match nil t) | 1862 (while (funcall search-func match nil t) |
1808 (and (= (progn (beginning-of-line) (point)) | 1863 (and (= (gnus-point-at-bol) |
1809 (match-beginning 0)) | 1864 (match-beginning 0)) |
1810 (= (progn (end-of-line) (point)) | 1865 (= (progn (end-of-line) (point)) |
1811 (match-end 0)) | 1866 (match-end 0)) |
1812 (progn | 1867 (progn |
1813 (setq found (setq arts (get-text-property | 1868 (setq found (setq arts (get-text-property |
1822 (while (funcall search-func match nil t) | 1877 (while (funcall search-func match nil t) |
1823 (end-of-line) | 1878 (end-of-line) |
1824 (setq found (setq arts (get-text-property (point) 'articles))) | 1879 (setq found (setq arts (get-text-property (point) 'articles))) |
1825 ;; Found a match, update scores. | 1880 ;; Found a match, update scores. |
1826 (while (setq art (pop arts)) | 1881 (while (setq art (pop arts)) |
1882 (setcdr art (+ score (cdr art))) | |
1883 (when trace | |
1884 (push (cons | |
1885 (car-safe (rassq alist gnus-score-cache)) | |
1886 kill) | |
1887 gnus-score-trace)) | |
1827 (when (setq new (gnus-score-add-followups | 1888 (when (setq new (gnus-score-add-followups |
1828 (car art) score all-scores thread)) | 1889 (car art) score all-scores thread)) |
1829 (push new news))))) | 1890 (push new news))))) |
1830 ;; Update expire date | 1891 ;; Update expire date |
1831 (cond ((null date)) ;Permanent entry. | 1892 (cond ((null date)) ;Permanent entry. |
1869 ;; than EXPIRE. | 1930 ;; than EXPIRE. |
1870 | 1931 |
1871 ;; Insert the unique article headers in the buffer. | 1932 ;; Insert the unique article headers in the buffer. |
1872 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) | 1933 (let ((gnus-score-index (nth 1 (assoc header gnus-header-index))) |
1873 ;; gnus-score-index is used as a free variable. | 1934 ;; gnus-score-index is used as a free variable. |
1874 (simplify (and gnus-score-thread-simplify | 1935 (simplify (and gnus-score-thread-simplify |
1875 (string= "subject" header))) | 1936 (string= "subject" header))) |
1876 alike last this art entries alist articles | 1937 alike last this art entries alist articles |
1877 fuzzies arts words kill) | 1938 fuzzies arts words kill) |
1878 | 1939 |
1879 ;; Sorting the articles costs os O(N*log N) but will allow us to | 1940 ;; Sorting the articles costs os O(N*log N) but will allow us to |
1880 ;; only match with each unique header. Thus the actual matching | 1941 ;; only match with each unique header. Thus the actual matching |
1895 | 1956 |
1896 ;; If we're working with non-standard headers, we are stuck | 1957 ;; If we're working with non-standard headers, we are stuck |
1897 ;; with working on them as a group. What a hassle. | 1958 ;; with working on them as a group. What a hassle. |
1898 ;; Just wait 'til you see what horrors we commit against `match'... | 1959 ;; Just wait 'til you see what horrors we commit against `match'... |
1899 (if (= gnus-score-index 9) | 1960 (if (= gnus-score-index 9) |
1900 (setq this (prin1-to-string this))) ; ick. | 1961 (setq this (gnus-prin1-to-string this))) ; ick. |
1901 | 1962 |
1902 (if simplify | 1963 (if simplify |
1903 (setq this (gnus-map-function gnus-simplify-subject-functions this))) | 1964 (setq this (gnus-map-function gnus-simplify-subject-functions this))) |
1904 (if (equal last this) | 1965 (if (equal last this) |
1905 ;; O(N*H) cons-cells used here, where H is the number of | 1966 ;; O(N*H) cons-cells used here, where H is the number of |
1934 (mt (aref (symbol-name type) 0)) | 1995 (mt (aref (symbol-name type) 0)) |
1935 (case-fold-search (not (memq mt '(?R ?S ?E ?F)))) | 1996 (case-fold-search (not (memq mt '(?R ?S ?E ?F)))) |
1936 (dmt (downcase mt)) | 1997 (dmt (downcase mt)) |
1937 ;; Assume user already simplified regexp and fuzzies | 1998 ;; Assume user already simplified regexp and fuzzies |
1938 (match (if (and simplify (not (memq dmt '(?f ?r)))) | 1999 (match (if (and simplify (not (memq dmt '(?f ?r)))) |
1939 (gnus-map-function | 2000 (gnus-map-function |
1940 gnus-simplify-subject-functions | 2001 gnus-simplify-subject-functions |
1941 (nth 0 kill)) | 2002 (nth 0 kill)) |
1942 (nth 0 kill))) | 2003 (nth 0 kill))) |
1943 (search-func | 2004 (search-func |
1944 (cond ((= dmt ?r) 're-search-forward) | 2005 (cond ((= dmt ?r) 're-search-forward) |
1945 ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward) | 2006 ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward) |
1946 ((= dmt ?w) nil) | 2007 ((= dmt ?w) nil) |
1947 (t (error "Invalid match type: %s" type))))) | 2008 (t (error "Invalid match type: %s" type))))) |
1948 | 2009 |
1949 ;; Evil hackery to make match usable in non-standard headers. | 2010 ;; Evil hackery to make match usable in non-standard headers. |
1950 (when extra | 2011 (when extra |
1951 (setq match (concat "[ (](" extra " \\. \"[^)]*" | 2012 (setq match (concat "[ (](" extra " \\. \"[^)]*" |
1952 match "[^(]*\")[ )]") | 2013 match "[^\"]*\")[ )]") |
1953 search-func 're-search-forward)) ; XXX danger?!? | 2014 search-func 're-search-forward)) ; XXX danger?!? |
1954 | 2015 |
1955 (cond | 2016 (cond |
1956 ;; Fuzzy matches. We save these for later. | 2017 ;; Fuzzy matches. We save these for later. |
1957 ((= dmt ?f) | 2018 ((= dmt ?f) |
2273 (goto-char (point-min)) | 2334 (goto-char (point-min)) |
2274 (while (re-search-forward "\\b\\w+\\b" nil t) | 2335 (while (re-search-forward "\\b\\w+\\b" nil t) |
2275 ;; Put the word and score into the hashtb. | 2336 ;; Put the word and score into the hashtb. |
2276 (setq val (gnus-gethash (setq word (match-string 0)) | 2337 (setq val (gnus-gethash (setq word (match-string 0)) |
2277 hashtb)) | 2338 hashtb)) |
2278 (setq val (+ score (or val 0))) | 2339 (when (or (not gnus-adaptive-word-length-limit) |
2279 (if (and gnus-adaptive-word-minimum | 2340 (> (length word) |
2280 (< val gnus-adaptive-word-minimum)) | 2341 gnus-adaptive-word-length-limit)) |
2281 (setq val gnus-adaptive-word-minimum)) | 2342 (setq val (+ score (or val 0))) |
2282 (gnus-sethash word val hashtb)) | 2343 (if (and gnus-adaptive-word-minimum |
2344 (< val gnus-adaptive-word-minimum)) | |
2345 (setq val gnus-adaptive-word-minimum)) | |
2346 (gnus-sethash word val hashtb))) | |
2283 (erase-buffer)))) | 2347 (erase-buffer)))) |
2284 (set-syntax-table syntab)) | 2348 (set-syntax-table syntab)) |
2285 ;; Make all the ignorable words ignored. | 2349 ;; Make all the ignorable words ignored. |
2286 (let ((ignored (append gnus-ignored-adaptive-words | 2350 (let ((ignored (append gnus-ignored-adaptive-words |
2287 (if gnus-adaptive-word-no-group-words | 2351 (if gnus-adaptive-word-no-group-words |
2316 (interactive) | 2380 (interactive) |
2317 (let ((old-scored gnus-newsgroup-scored)) | 2381 (let ((old-scored gnus-newsgroup-scored)) |
2318 (let ((gnus-newsgroup-headers | 2382 (let ((gnus-newsgroup-headers |
2319 (list (gnus-summary-article-header))) | 2383 (list (gnus-summary-article-header))) |
2320 (gnus-newsgroup-scored nil) | 2384 (gnus-newsgroup-scored nil) |
2321 trace) | 2385 ;; Must be synced with `gnus-score-edit-file-at-point': |
2386 (frmt "%S [%s] -> %s\n") | |
2387 trace | |
2388 file) | |
2322 (save-excursion | 2389 (save-excursion |
2323 (nnheader-set-temp-buffer "*Score Trace*")) | 2390 (nnheader-set-temp-buffer "*Score Trace*")) |
2324 (setq gnus-score-trace nil) | 2391 (setq gnus-score-trace nil) |
2325 (gnus-possibly-score-headers 'trace) | 2392 (gnus-possibly-score-headers 'trace) |
2326 (if (not (setq trace gnus-score-trace)) | 2393 (if (not (setq trace gnus-score-trace)) |
2327 (gnus-error | 2394 (gnus-error |
2328 1 "No score rules apply to the current article (default score %d)." | 2395 1 "No score rules apply to the current article (default score %d)." |
2329 gnus-summary-default-score) | 2396 gnus-summary-default-score) |
2330 (set-buffer "*Score Trace*") | 2397 (set-buffer "*Score Trace*") |
2398 ;; Use a keymap instead? | |
2399 (local-set-key "q" | |
2400 (lambda () | |
2401 (interactive) | |
2402 (bury-buffer nil) | |
2403 (gnus-summary-expand-window))) | |
2404 (local-set-key "e" (lambda () | |
2405 "Run `gnus-score-edit-file-at-point'." | |
2406 (interactive) | |
2407 (gnus-score-edit-file-at-point))) | |
2408 (local-set-key "f" (lambda () | |
2409 "Run `gnus-score-edit-file-at-point'." | |
2410 (interactive) | |
2411 (gnus-score-edit-file-at-point 'format))) | |
2412 (local-set-key "t" 'toggle-truncate-lines) | |
2331 (setq truncate-lines t) | 2413 (setq truncate-lines t) |
2332 (while trace | 2414 (dolist (entry trace) |
2333 (insert (format "%S -> %s\n" (cdar trace) | 2415 (setq file (or (car entry) |
2334 (or (caar trace) "(non-file rule)"))) | 2416 ;; Must be synced with |
2335 (setq trace (cdr trace))) | 2417 ;; `gnus-score-edit-file-at-point': |
2418 "(non-file rule)")) | |
2419 (insert | |
2420 (format frmt | |
2421 (cdr entry) | |
2422 ;; Don't use `file-name-sans-extension' to see .SCORE and | |
2423 ;; .ADAPT directly: | |
2424 (file-name-nondirectory file) | |
2425 (abbreviate-file-name file)))) | |
2426 (insert | |
2427 "\n\nQuick help: | |
2428 | |
2429 Type `e' to edit score file corresponding to the score rule on current line, | |
2430 `f' to format (pretty print) the score file and edit it, | |
2431 `t' toggle to truncate long lines in this buffer, | |
2432 `q' to quit. | |
2433 | |
2434 The first sexp on each line is the score rule, followed by the file name of | |
2435 the score file and its full name, including the directory.") | |
2336 (goto-char (point-min)) | 2436 (goto-char (point-min)) |
2337 (gnus-configure-windows 'score-trace))) | 2437 (gnus-configure-windows 'score-trace))) |
2338 (set-buffer gnus-summary-buffer) | 2438 (set-buffer gnus-summary-buffer) |
2339 (setq gnus-newsgroup-scored old-scored))) | 2439 (setq gnus-newsgroup-scored old-scored))) |
2340 | 2440 |
2458 (gnus-summary-raise-same-subject (- score))) | 2558 (gnus-summary-raise-same-subject (- score))) |
2459 | 2559 |
2460 (defun gnus-summary-lower-thread (&optional score) | 2560 (defun gnus-summary-lower-thread (&optional score) |
2461 "Lower score of articles in the current thread with SCORE." | 2561 "Lower score of articles in the current thread with SCORE." |
2462 (interactive "P") | 2562 (interactive "P") |
2463 (gnus-summary-raise-thread (- (1- (gnus-score-delta-default score))))) | 2563 (gnus-summary-raise-thread (- (gnus-score-delta-default score)))) |
2464 | 2564 |
2465 ;;; Finding score files. | 2565 ;;; Finding score files. |
2466 | 2566 |
2467 (defun gnus-score-score-files (group) | 2567 (defun gnus-score-score-files (group) |
2468 "Return a list of all possible score files." | 2568 "Return a list of all possible score files." |
2520 ;; Add files to the list of score files. | 2620 ;; Add files to the list of score files. |
2521 ((string-match regexp file) | 2621 ((string-match regexp file) |
2522 (push file out)))) | 2622 (push file out)))) |
2523 (or out | 2623 (or out |
2524 ;; Return a dummy value. | 2624 ;; Return a dummy value. |
2525 (list "~/News/this.file.does.not.exist.SCORE")))) | 2625 (list (expand-file-name "this.file.does.not.exist.SCORE" |
2626 gnus-kill-files-directory))))) | |
2526 | 2627 |
2527 (defun gnus-score-file-regexp () | 2628 (defun gnus-score-file-regexp () |
2528 "Return a regexp that match all score files." | 2629 "Return a regexp that match all score files." |
2529 (concat "\\(" (regexp-quote gnus-score-file-suffix ) | 2630 (concat "\\(" (regexp-quote gnus-score-file-suffix ) |
2530 "\\|" (regexp-quote gnus-adaptive-file-suffix) "\\)\\'")) | 2631 "\\|" (regexp-quote gnus-adaptive-file-suffix) "\\)\\'")) |
2601 (not (string-match regexp group-trans)))) | 2702 (not (string-match regexp group-trans)))) |
2602 (and (not not-match) | 2703 (and (not not-match) |
2603 (ignore-errors (string-match regexp group-trans)))) | 2704 (ignore-errors (string-match regexp group-trans)))) |
2604 (push (car sfiles) ofiles))) | 2705 (push (car sfiles) ofiles))) |
2605 (setq sfiles (cdr sfiles))) | 2706 (setq sfiles (cdr sfiles))) |
2606 (kill-buffer (current-buffer)) | 2707 (gnus-kill-buffer (current-buffer)) |
2607 ;; Slight kludge here - the last score file returned should be | 2708 ;; Slight kludge here - the last score file returned should be |
2608 ;; the local score file, whether it exists or not. This is so | 2709 ;; the local score file, whether it exists or not. This is so |
2609 ;; that any score commands the user enters will go to the right | 2710 ;; that any score commands the user enters will go to the right |
2610 ;; file, and not end up in some global score file. | 2711 ;; file, and not end up in some global score file. |
2611 (let ((localscore (gnus-score-file-name group))) | 2712 (let ((localscore (gnus-score-file-name group))) |
2733 (push param-file score-files) | 2834 (push param-file score-files) |
2734 (setq gnus-newsgroup-adaptive-score-file param-file)))) | 2835 (setq gnus-newsgroup-adaptive-score-file param-file)))) |
2735 ;; Go through all the functions for finding score files (or actual | 2836 ;; Go through all the functions for finding score files (or actual |
2736 ;; scores) and add them to a list. | 2837 ;; scores) and add them to a list. |
2737 (while funcs | 2838 (while funcs |
2738 (when (gnus-functionp (car funcs)) | 2839 (when (functionp (car funcs)) |
2739 (setq score-files | 2840 (setq score-files |
2740 (nconc score-files (nreverse (funcall (car funcs) group))))) | 2841 (append score-files |
2842 (nreverse (funcall (car funcs) group))))) | |
2741 (setq funcs (cdr funcs))) | 2843 (setq funcs (cdr funcs))) |
2742 (when gnus-score-use-all-scores | 2844 (when gnus-score-use-all-scores |
2743 ;; Add any home score files. | 2845 ;; Add any home score files. |
2744 (let ((home (gnus-home-score-file group))) | 2846 (let ((home (gnus-home-score-file group))) |
2745 (when home | 2847 (when home |
2800 ;; available global score files. | 2902 ;; available global score files. |
2801 (interactive (list gnus-global-score-files)) | 2903 (interactive (list gnus-global-score-files)) |
2802 (let (out) | 2904 (let (out) |
2803 (while files | 2905 (while files |
2804 ;; #### /$ Unix-specific? | 2906 ;; #### /$ Unix-specific? |
2805 (if (string-match "/$" (car files)) | 2907 (if (file-directory-p (car files)) |
2806 (setq out (nconc (directory-files | 2908 (setq out (nconc (directory-files |
2807 (car files) t | 2909 (car files) t |
2808 (concat (gnus-score-file-regexp) "$")))) | 2910 (concat (gnus-score-file-regexp) "$")))) |
2809 (push (car files) out)) | 2911 (push (car files) out)) |
2810 (setq files (cdr files))) | 2912 (setq files (cdr files))) |
2835 (cond | 2937 (cond |
2836 ;; Simple string. | 2938 ;; Simple string. |
2837 ((stringp elem) | 2939 ((stringp elem) |
2838 elem) | 2940 elem) |
2839 ;; Function. | 2941 ;; Function. |
2840 ((gnus-functionp elem) | 2942 ((functionp elem) |
2841 (funcall elem group)) | 2943 (funcall elem group)) |
2842 ;; Regexp-file cons. | 2944 ;; Regexp-file cons. |
2843 ((consp elem) | 2945 ((consp elem) |
2844 (when (string-match (gnus-globalify-regexp (car elem)) group) | 2946 (when (string-match (gnus-globalify-regexp (car elem)) group) |
2845 (replace-match (cadr elem) t nil group)))))) | 2947 (replace-match (cadr elem) t nil group)))))) |
2846 (when found | 2948 (when found |
2949 (setq found (nnheader-translate-file-chars found)) | |
2847 (if (file-name-absolute-p found) | 2950 (if (file-name-absolute-p found) |
2848 found | 2951 found |
2849 (nnheader-concat gnus-kill-files-directory found))))) | 2952 (nnheader-concat gnus-kill-files-directory found))))) |
2850 | 2953 |
2851 (defun gnus-hierarchial-home-score-file (group) | 2954 (defun gnus-hierarchial-home-score-file (group) |
2852 "Return the score file of the top-level hierarchy of GROUP." | 2955 "Return the score file of the top-level hierarchy of GROUP." |
2853 (if (string-match "^[^.]+\\." group) | 2956 (if (string-match "^[^.]+\\." group) |
2854 (concat (match-string 0 group) gnus-score-file-suffix) | 2957 (concat (match-string 0 group) gnus-score-file-suffix) |
2872 ;;; Score decays | 2975 ;;; Score decays |
2873 ;;; | 2976 ;;; |
2874 | 2977 |
2875 (defun gnus-decay-score (score) | 2978 (defun gnus-decay-score (score) |
2876 "Decay SCORE according to `gnus-score-decay-constant' and `gnus-score-decay-scale'." | 2979 "Decay SCORE according to `gnus-score-decay-constant' and `gnus-score-decay-scale'." |
2877 (floor | 2980 (let ((n (- score |
2878 (- score | 2981 (* (if (< score 0) -1 1) |
2879 (* (if (< score 0) -1 1) | 2982 (min (abs score) |
2880 (min (abs score) | 2983 (max gnus-score-decay-constant |
2881 (max gnus-score-decay-constant | 2984 (* (abs score) |
2882 (* (abs score) | 2985 gnus-score-decay-scale))))))) |
2883 gnus-score-decay-scale))))))) | 2986 (if (and (featurep 'xemacs) |
2987 ;; XEmacs' floor can handle only the floating point | |
2988 ;; number below the half of the maximum integer. | |
2989 (> (abs n) (lsh -1 -2))) | |
2990 (string-to-number | |
2991 (car (split-string (number-to-string n) "\\."))) | |
2992 (floor n)))) | |
2884 | 2993 |
2885 (defun gnus-decay-scores (alist day) | 2994 (defun gnus-decay-scores (alist day) |
2886 "Decay non-permanent scores in ALIST." | 2995 "Decay non-permanent scores in ALIST." |
2887 (let ((times (- (time-to-days (current-time)) day)) | 2996 (let ((times (- (time-to-days (current-time)) day)) |
2888 kill entry updated score n) | 2997 kill entry updated score n) |
2911 cons cell (SYM . STRING), where the symbol SYM is `new' or `bad'. | 3020 cons cell (SYM . STRING), where the symbol SYM is `new' or `bad'. |
2912 In the `new' case, the string is a safe replacement for REGEXP. | 3021 In the `new' case, the string is a safe replacement for REGEXP. |
2913 In the `bad' case, the string is a unsafe subexpression of REGEXP, | 3022 In the `bad' case, the string is a unsafe subexpression of REGEXP, |
2914 and we do not have a simple replacement to suggest. | 3023 and we do not have a simple replacement to suggest. |
2915 | 3024 |
2916 See `(Gnus)Scoring Tips' for examples of good regular expressions." | 3025 See Info node `(gnus)Scoring Tips' for examples of good regular expressions." |
2917 (let (case-fold-search) | 3026 (let (case-fold-search) |
2918 (and | 3027 (and |
2919 ;; First, try a relatively fast necessary condition. | 3028 ;; First, try a relatively fast necessary condition. |
2920 ;; Notice ranges (like [^:] or [\t-\r]), \s>, \Sw, \W, \', \`: | 3029 ;; Notice ranges (like [^:] or [\t-\r]), \s>, \Sw, \W, \', \`: |
2921 (string-match "\n\\|\\\\[SsW`']\\|\\[\\^\\|[\0-\n]-" regexp) | 3030 (string-match "\n\\|\\\\[SsW`']\\|\\[\\^\\|[\0-\n]-" regexp) |
2959 (new (cons 'new new)) | 3068 (new (cons 'new new)) |
2960 (t nil)))))) | 3069 (t nil)))))) |
2961 | 3070 |
2962 (provide 'gnus-score) | 3071 (provide 'gnus-score) |
2963 | 3072 |
3073 ;;; arch-tag: d3922589-764d-46ae-9954-9330fd192634 | |
2964 ;;; gnus-score.el ends here | 3074 ;;; gnus-score.el ends here |