1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-31 20:02:42 +00:00

Allow user-defined scoring in Gnus

* lisp/gnus/gnus-score.el (gnus-score-func): New function (bug#43413).
* doc/misc/gnus.texi (Score File Format): Document it.
This commit is contained in:
Alex Bochannek 2020-09-17 17:02:48 +02:00 committed by Lars Ingebrigtsen
parent 82de8ecc08
commit 12aea1fa80
3 changed files with 79 additions and 10 deletions

View File

@ -20394,6 +20394,36 @@ key will lead to creation of @file{ADAPT} files.)
@end enumerate
@cindex score file atoms
@item score-fn
The value of this entry should be one or more user-defined function
names in parentheses. Each function will be called in order and the
returned value is required to be an integer.
@example
(score-fn (custom-scoring))
@end example
The user-defined function is called with an associative list with the
keys @code{number subject from date id refs chars lines xref extra}
followed by the article's score before the function is run.
The following (somewhat contrived) example shows how to use a
user-defined function that increases an article's score by 10 if the
year of the article's date is also mentioned in its subject.
@example
(defun custom-scoring (article-alist score)
(let ((subject (cdr (assoc 'subject article-alist)))
(date (cdr (assoc 'date article-alist))))
(if (string-match (number-to-string
(nth 5 (parse-time-string date)))
subject)
10)))
@end example
@code{score-fn} entries are permanent and can only be added or
modified directly in the @code{SCORE} file.
@item mark
The value of this entry should be a number. Any articles with a score
lower than this number will be marked as read.

View File

@ -365,6 +365,11 @@ tags to be considered as well.
You can now score based on the relative age of an article with the new
'<' and '>' date scoring types.
+++
*** User-defined scoring is now possible.
The new type is 'score-fn'. More information in
(Gnus)Score File Format.
+++
*** New backend 'nnselect'.
The newly added 'nnselect' backend allows creating groups from an

View File

@ -25,8 +25,6 @@
;;; Code:
(eval-when-compile (require 'cl-lib))
(require 'gnus)
(require 'gnus-sum)
(require 'gnus-art)
@ -35,6 +33,7 @@
(require 'message)
(require 'score-mode)
(require 'gmm-utils)
(require 'cl-lib)
(defcustom gnus-global-score-files nil
"List of global score files and directories.
@ -497,6 +496,7 @@ of the last successful match.")
("head" -1 gnus-score-body)
("body" -1 gnus-score-body)
("all" -1 gnus-score-body)
(score-fn -1 nil)
("followup" 2 gnus-score-followup)
("thread" 5 gnus-score-thread)))
@ -1175,14 +1175,19 @@ If FORMAT, also format the current score file."
(when format
(gnus-score-pretty-print))
(when (consp rule) ;; the rule exists
(setq rule (mapconcat #'(lambda (obj)
(regexp-quote (format "%S" obj)))
rule
sep))
(setq rule (if (symbolp (car rule))
(format "(%S)" (car rule))
(mapconcat #'(lambda (obj)
(regexp-quote (format "%S" obj)))
rule
sep)))
(goto-char (point-min))
(re-search-forward rule nil t)
;; make it easy to use `kill-sexp':
(goto-char (1- (match-beginning 0)))))))
(let ((move (if (string-match "(.*)" rule)
0
-1)))
(re-search-forward rule nil t)
;; make it easy to use `kill-sexp':
(goto-char (+ move (match-beginning 0))))))))
(defun gnus-score-load-file (file)
;; Load score file FILE. Returns a list a retrieved score-alists.
@ -1232,6 +1237,7 @@ If FORMAT, also format the current score file."
(let ((mark (car (gnus-score-get 'mark alist)))
(expunge (car (gnus-score-get 'expunge alist)))
(mark-and-expunge (car (gnus-score-get 'mark-and-expunge alist)))
(score-fn (car (gnus-score-get 'score-fn alist)))
(files (gnus-score-get 'files alist))
(exclude-files (gnus-score-get 'exclude-files alist))
(orphan (car (gnus-score-get 'orphan alist)))
@ -1567,10 +1573,14 @@ If FORMAT, also format the current score file."
(gnus-message
7 "Scoring on headers or body skipped.")
nil)
;; Run score-fn
(if (eq header 'score-fn)
(setq new (gnus-score-func scores trace))
;; Call the scoring function for this type of "header".
(setq new (funcall (nth 2 entry) scores header
now expire trace)))
now expire trace))))
(push new news))))
(when (gnus-buffer-live-p gnus-summary-buffer)
(let ((scored gnus-newsgroup-scored))
(with-current-buffer gnus-summary-buffer
@ -1636,6 +1646,30 @@ score in `gnus-newsgroup-scored' by SCORE."
(not (string= id "")))
(gnus-score-lower-thread thread score)))))
(defun gnus-score-func (scores &optional trace)
(dolist (alist scores)
(let ((articles gnus-scores-articles)
(entries (assoc 'score-fn alist)))
(dolist (score-fn (cdr entries))
(let ((score-fn (car score-fn))
article-alist score fn-score)
(dolist (art articles)
(setq article-alist
(cl-pairlis
'(number subject from date id
refs chars lines xref extra)
(car art))
score (cdr art))
(when (integerp (setq fn-score (funcall score-fn
article-alist score)))
(setcdr art (+ score fn-score)))
(setq score (cdr art))
(when (and trace
(integerp fn-score))
(push (cons (car-safe (rassq alist gnus-score-cache))
(list score-fn fn-score))
gnus-score-trace))))))))
(defun gnus-score-integer (scores header now expire &optional trace)
(let ((gnus-score-index (nth 1 (assoc header gnus-header-index)))
entries alist)