Gnus development mailing list
 help / color / mirror / Atom feed
From: Karl Kleinpaste <karl@jprc.com>
Subject: Re: new NOV stuff in p0.40
Date: 28 Oct 1998 00:51:53 -500	[thread overview]
Message-ID: <vxkd87dw7wm.fsf@pocari-sweat.jprc.com> (raw)
In-Reply-To: Lars Magne Ingebrigtsen's message of "26 Oct 1998 03:48:55 +0100"

Karl Kleinpaste <karl@jprc.com> writes:
>> Since you consider this easy :-), I believe I'll wait a day or three
>> to see if you come up with something; if not, I'll see if I can get my
>> elisp karma worked up to produce something sensible.

Lars Magne Ingebrigtsen <larsi@gnus.org> writes:
> I think I'll leave it to you.  :-)

Well, you asked for it.

Here's a pile of updated code for p0.40.  Even though you recommended
against it, I thought I could get away with using gnus-score-string
directly, and I think I nearly succeeded. :-)  Unfortunately, there
may be a couple of sacrifices that were made in the attempt.

What's in the patch below:

1. Minor additions to tables in gnus-{cus,sum}.el.
2. A serious bugfix to gnus-nov-parse-extra in gnus-sum.el; this is
probably the bug you noticed a few evenings ago, and the fix is pretty 
obvious; I'd be surprised if it varies at all from what you now have.
3. Lots o' stuff (most of the patch) in gnus-score.el:
- Additions to doc strings & tables.
- Querying user for what extra header to score.
- Passing an extra arg to gnus-summary-score-entry and
  gnus-summary-score-effect.
- Hacking out a specific extra header in gnus-summary-header.
- Handling extra cases in gnus-score-string because the extras aren't
  a string.  There is dark evil here.  I really didn't know what I was 
  getting into until I got to this point and found myself facing what
  appeared to me to be a backward-ordered matching structure; this is
  probably the big argument in favor of not having used
  gnus-score-string in the 1st place...but frankly, I was too far in
  to let it go, because by then I'd slaughtered my working 0.40 tree
  and had to make it work before I could let myself get some sleep. :-)

I'm posting this to the list in the hopes that some folks out there
will be interested in taking a look (and perhaps telling me how
foolish I was for not taking that original suggestion to create
gnus-score-extra rather than retrofitting gnus-score-string the way
I've done here -- my elisp karma is not as strong as perhaps it ought
to be).

What these changes produce is scorefile behavior which uses elements
containing a 5th field, e.g.,
	(("extra"
	  ("gnus" nil nil s "Keywords")))
There is an add'l query during e.g. `I e s p' in which Gnus now asks
what header it is that you want scored.  This does a completing read
against the symbols in gnus-extra-headers, on the theory that you
probably should be concerned only with scoring extra headers of which
you have awareness anyhow.

Please give it a try.  I'm wide open to critique, addition, change, or
utter rewrite.

In a day or so, I'll send a module I've been using for a couple years 
to auto-generate Keywords within Gnus at posting time, too, so that
people who can score on Keywords have something useful to chew on.

--karl

--- gnus-cus.el.orig	Thu Sep 24 14:32:01 1998
+++ gnus-cus.el	Tue Oct 27 16:53:41 1998
@@ -581,12 +581,13 @@
 			 `(checklist :inline t
 				     :greedy t
 				     (gnus-score-string :tag "From")
 				     (gnus-score-string :tag "Subject")
 				     (gnus-score-string :tag "References")
 				     (gnus-score-string :tag "Xref")
+				     (gnus-score-string :tag "Extra")
 				     (gnus-score-string :tag "Message-ID")
 				     (gnus-score-integer :tag "Lines")
 				     (gnus-score-integer :tag "Chars")
 				     (gnus-score-date :tag "Date")
 				     (gnus-score-string :tag "Head"
 							:doc "\
--- gnus-sum.el.orig	Sun Oct 25 17:13:17 1998
+++ gnus-sum.el	Tue Oct 27 18:18:45 1998
@@ -1818,12 +1818,13 @@
       nil
     (let ((headers '(("author" "from" string)
 		     ("subject" "subject" string)
 		     ("article body" "body" string)
 		     ("article head" "head" string)
 		     ("xref" "xref" string)
+		     ("extra header" "extra" string)
 		     ("lines" "lines" number)
 		     ("followups to author" "followup" string)))
 	  (types '((number ("less than" <)
 			   ("greater than" >)
 			   ("equal" =))
 		   (string ("substring" s)
@@ -3125,14 +3126,14 @@
   '(buffer-substring (point) (if (gnus-nov-skip-field) (1- (point)) eol)))
 
 (defmacro gnus-nov-parse-extra ()
   '(let (out string)
      (while (not (memq (char-after) '(?\n nil)))
        (setq string (gnus-nov-field))
-       (when (string-match "^\\([^ :]\\): " string)
-	 (push (cons (intern (match-string 1))
+       (when (string-match "^\\([^ :]+\\): " string)
+	 (push (cons (intern (match-string 1 string))
 		     (substring string (match-end 0)))
 	       out)))
      out))
 
 ;; This function has to be called with point after the article number
 ;; on the beginning of the line.
--- gnus-score.el.orig	Sat Oct 10 20:32:03 1998
+++ gnus-score.el	Wed Oct 28 00:36:26 1998
@@ -305,12 +305,13 @@
  s: subject
  b: body
  h: head
  i: message-id
  t: references
  x: xref
+ e: `extra' (non-standard overview)
  l: lines
  d: date
  f: followup
 
 If nil, the user will be asked for a header."
   :group 'gnus-score-default
@@ -318,12 +319,13 @@
 		 (const :tag "subject" s)
 		 (const :tag "body" b)
 		 (const :tag "head" h)
 		 (const :tag "message-id" i)
 		 (const :tag "references" t)
 		 (const :tag "xref" x)
+		 (const :tag "extra" e)
 		 (const :tag "lines" l)
 		 (const :tag "date" d)
 		 (const :tag "followup" f)
 		 (const :tag "ask" nil)))
 
 (defcustom gnus-score-default-type nil
@@ -441,12 +443,13 @@
     ("date" 3 gnus-score-date)
     ("message-id" 4 gnus-score-string)
     ("references" 5 gnus-score-string)
     ("chars" 6 gnus-score-integer)
     ("lines" 7 gnus-score-integer)
     ("xref" 8 gnus-score-string)
+    ("extra" 9 gnus-score-string)
     ("head" -1 gnus-score-body)
     ("body" -1 gnus-score-body)
     ("all" -1 gnus-score-body)
     ("followup" 2 gnus-score-followup)
     ("thread" 5 gnus-score-thread)))
 
@@ -499,12 +502,13 @@
 	    (?s "subject" nil nil string)
 	    (?b "body" "" nil body-string)
 	    (?h "head" "" nil body-string)
 	    (?i "message-id" nil t string)
 	    (?r "references" "message-id" nil string)
 	    (?x "xref" nil nil string)
+	    (?e "extra" nil nil string)
 	    (?l "lines" nil nil number)
 	    (?d "date" nil nil date)
 	    (?f "followup" nil nil string)
 	    (?t "thread" "message-id" nil string)))
 	 (char-to-type
 	  '((?s s "substring" string)
@@ -527,13 +531,13 @@
 	 (hchar (and gnus-score-default-header
 		     (aref (symbol-name gnus-score-default-header) 0)))
 	 (tchar (and gnus-score-default-type
 		     (aref (symbol-name gnus-score-default-type) 0)))
 	 (pchar (and gnus-score-default-duration
 		     (aref (symbol-name gnus-score-default-duration) 0)))
-	 entry temporary type match)
+	 entry temporary type match extra)
 
     (unwind-protect
 	(progn
 
 	  ;; First we read the header to score.
 	  (while (not hchar)
@@ -619,15 +623,32 @@
 	    (if mimic
 		(error "%c %c %c %c" prefix hchar tchar pchar)
 	      (error "Illegal match duration"))))
       ;; Always kill the score help buffer.
       (gnus-score-kill-help-buffer))
 
+    ;; If scoring an extra (non-standard overview) header,
+    ;; we must find out which header is in question.
+    (setq extra
+	  (and gnus-extra-headers
+	       (equal (nth 1 entry) "extra")
+	       (intern					; need symbol
+		(gnus-completing-read
+		 (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
+    ;; extra is now nil or a symbol.
+
     ;; We have all the data, so we enter this score.
     (setq match (if (string= (nth 2 entry) "") ""
-		  (gnus-summary-header (or (nth 2 entry) (nth 1 entry)))))
+		  (gnus-summary-header (or (nth 2 entry) (nth 1 entry))
+				       nil extra)))
 
     ;; Modify the match, perhaps.
     (cond
      ((equal (nth 1 entry) "xref")
       (when (string-match "^Xref: *" match)
 	(setq match (substring match (match-end 0))))
@@ -657,13 +678,15 @@
      match				; Match
      type				; Type
      (if (eq score 's) nil score)	; Score
      (if (eq temporary 'perm)		; Temp
 	 nil
        temporary)
-     (not (nth 3 entry)))		; Prompt
+     (not (nth 3 entry))		; Prompt
+     nil				; not silent 
+     extra)				; non-standard overview.
 
     (when (eq symp 'a)
       ;; We change the score file back to the previous one.
       (save-excursion
 	(set-buffer gnus-summary-buffer)
 	(gnus-score-load-file current-score-file)))))
@@ -706,20 +729,22 @@
     (split-window)
     (pop-to-buffer "*Score Help*")
     (let ((window-min-height 1))
       (shrink-window-if-larger-than-buffer))
     (select-window (get-buffer-window gnus-summary-buffer))))
 
-(defun gnus-summary-header (header &optional no-err)
+(defun gnus-summary-header (header &optional no-err extra)
   ;; Return HEADER for current articles, or error.
   (let ((article (gnus-summary-article-number))
 	headers)
     (if article
 	(if (and (setq headers (gnus-summary-article-header article))
 		 (vectorp headers))
-	    (aref headers (nth 1 (assoc header gnus-header-index)))
+	    (if extra			; `header' must be "extra"
+		(or (cdr (assq extra (mail-header-extra headers))) "")
+	      (aref headers (nth 1 (assoc header gnus-header-index))))
 	  (if no-err
 	      nil
 	    (error "Pseudo-articles can't be scored")))
       (if no-err
 	  (error "No article on current line")
 	nil))))
@@ -739,22 +764,23 @@
   (cdr (assoc symbol
 	      (or alist
 		  gnus-score-alist
 		  (gnus-newsgroup-score-alist)))))
 
 (defun gnus-summary-score-entry (header match type score date
-					&optional prompt silent)
+					&optional prompt silent extra)
   (interactive)
   "Enter score file entry.
 HEADER is the header being scored.
 MATCH is the string we are looking for.
 TYPE is the match type: substring, regexp, exact, fuzzy.
 SCORE is the score to add.
 DATE is the expire date, or nil for no expire, or 'now for immediate expire.
 If optional argument `PROMPT' is non-nil, allow user to edit match.
-If optional argument `SILENT' is nil, show effect of score entry."
+If optional argument `SILENT' is nil, show effect of score entry.
+If optional argument `EXTRA' is non-nil, it's a non-standard overview header."
   ;; Regexp is the default type.
   (when (eq type t)
     (setq type 'r))
   ;; Simplify matches...
   (cond ((or (eq type 'r) (eq type 's) (eq type nil))
 	 (setq match (if match (gnus-simplify-subject-re match) "")))
@@ -789,12 +815,17 @@
       (when (= score gnus-score-interactive-default-score)
 	(setq score nil))
       (let ((old (gnus-score-get header))
 	    elem)
 	(setq new
 	      (cond
+	       (extra
+		(list match score
+		      (and date (if (numberp date) date
+				  (date-to-day date)))
+		      type (symbol-name extra)))
 	       (type
 		(list match score
 		      (and date (if (numberp date) date
 				  (date-to-day date)))
 		      type))
 	       (date (list match score (date-to-day date)))
@@ -819,24 +850,25 @@
 
     ;; Score the current buffer.
     (unless silent
       (if (and (>= (nth 1 (assoc header gnus-header-index)) 0)
 	       (eq (nth 2 (assoc header gnus-header-index))
 		   'gnus-score-string))
-	  (gnus-summary-score-effect header match type score)
+	  (gnus-summary-score-effect header match type score extra)
 	(gnus-summary-rescore)))
 
     ;; Return the new scoring rule.
     new))
 
-(defun gnus-summary-score-effect (header match type score)
+(defun gnus-summary-score-effect (header match type score extra)
   "Simulate the effect of a score file entry.
 HEADER is the header being scored.
 MATCH is the string we are looking for.
 TYPE is the score type.
-SCORE is the score to add."
+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)
 		     (read-string "Match: ")
 		     (y-or-n-p "Use regexp match? ")
@@ -851,13 +883,13 @@
 			 match)
 			((eq type 'e)
 			 (concat "\\`" (regexp-quote match) "\\'"))
 			(t
 			 (regexp-quote match)))))
       (while (not (eobp))
-	(let ((content (gnus-summary-header header 'noerr))
+	(let ((content (gnus-summary-header header 'noerr extra))
 	      (case-fold-search t))
 	  (and content
 	       (when (if (eq type 'f)
 			 (string-equal (gnus-simplify-subject-fuzzy content)
 				       regexp)
 		       (string-match regexp content))
@@ -1863,18 +1895,29 @@
     ;; Sorting the articles costs os O(N*log N) but will allow us to
     ;; only match with each unique header.  Thus the actual matching
     ;; will be O(M*U) where M is the number of strings to match with,
     ;; and U is the number of unique headers.  It is assumed (but
     ;; untested) this will be a net win because of the large constant
     ;; factor involved with string matching.
-    (setq gnus-scores-articles (sort gnus-scores-articles 'gnus-score-string<)
+    (setq gnus-scores-articles
+	  ;; We cannot string-sort the extra headers list.  *sigh*
+	  (if (= gnus-score-index 9)
+	      gnus-scores-articles
+	    (sort gnus-scores-articles 'gnus-score-string<))
 	  articles gnus-scores-articles)
 
     (erase-buffer)
     (while (setq art (pop articles))
       (setq this (aref (car art) gnus-score-index))
+
+      ;; If we're working with non-standard headers, we are stuck
+      ;; 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.
+
       (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.
 	  (push art alike)
@@ -1899,12 +1942,13 @@
 	    entries (assoc header alist))
       (while (cdr entries)		;First entry is the header index.
 	(let* ((kill (cadr entries))
 	       (type (or (nth 3 kill) 's))
 	       (score (or (nth 1 kill) gnus-score-interactive-default-score))
 	       (date (nth 2 kill))
+	       (extra (nth 4 kill))	; non-standard header; string.
 	       (found nil)
 	       (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))))
@@ -1914,12 +1958,18 @@
                         (nth 0 kill)))
 	       (search-func
 		(cond ((= dmt ?r) 're-search-forward)
 		      ((or (= dmt ?e) (= dmt ?s) (= dmt ?f)) 'search-forward)
 		      ((= dmt ?w) nil)
 		      (t (error "Illegal match type: %s" type)))))
+
+	  ;; Evil hackery to make match usable in non-standard headers.
+	  (when extra
+	    (setq match (concat "[ (](" extra " \\. \".*" match ".*\")[ )]")
+		  search-func 're-search-forward))	; XXX danger?!?
+
 	  (cond
 	   ;; Fuzzy matches.  We save these for later.
 	   ((= dmt ?f)
 	    (push (cons entries alist) fuzzies)
 	    (setq entries (cdr entries)))
 	   ;; Word matches.  Save these for even later.


  reply	other threads:[~1998-10-28  5:51 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1998-10-26  0:18 Karl Kleinpaste
1998-10-26  0:37 ` Lars Magne Ingebrigtsen
1998-10-26  1:40   ` Karl Kleinpaste
1998-10-26  2:15     ` Karl Kleinpaste
1998-10-26  2:52       ` Lars Magne Ingebrigtsen
1998-10-26  8:17         ` Kai Grossjohann
1998-10-26  8:48           ` Lars Magne Ingebrigtsen
1998-10-26 10:12             ` Kai Grossjohann
1998-10-26  2:48     ` Lars Magne Ingebrigtsen
1998-10-28  5:51       ` Karl Kleinpaste [this message]
1998-10-28 13:38         ` Karl Kleinpaste

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=vxkd87dw7wm.fsf@pocari-sweat.jprc.com \
    --to=karl@jprc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).