mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
Improve mark handling in gnus nnselect
* lisp/gnus/nnselect.el (numbers-by-group,
nnselect-request-update-info, nnselect-push-info): Handle all three
mark types ('tuple, 'range, 'list) and general speedups.
This commit is contained in:
parent
e4831151c2
commit
6037051f49
1 changed files with 140 additions and 73 deletions
|
|
@ -203,11 +203,22 @@ as `(keyfunc member)' and the corresponding element is just
|
||||||
(nnselect-categorize ,articles 'nnselect-article-group
|
(nnselect-categorize ,articles 'nnselect-article-group
|
||||||
'nnselect-article-id)))
|
'nnselect-article-id)))
|
||||||
|
|
||||||
(define-inline numbers-by-group (articles)
|
(define-inline numbers-by-group (articles &optional type)
|
||||||
(inline-quote
|
(inline-quote
|
||||||
(nnselect-categorize
|
(cond
|
||||||
,articles 'nnselect-article-group 'nnselect-article-number)))
|
((eq ,type 'range)
|
||||||
|
(nnselect-categorize (gnus-uncompress-range ,articles)
|
||||||
|
'nnselect-article-group 'nnselect-article-number))
|
||||||
|
((eq ,type 'tuple)
|
||||||
|
(nnselect-categorize ,articles
|
||||||
|
#'(lambda (elem)
|
||||||
|
(nnselect-article-group (car elem)))
|
||||||
|
#'(lambda (elem)
|
||||||
|
(cons (nnselect-article-number
|
||||||
|
(car elem)) (cdr elem)))))
|
||||||
|
(t
|
||||||
|
(nnselect-categorize ,articles
|
||||||
|
'nnselect-article-group 'nnselect-article-number)))))
|
||||||
|
|
||||||
(defmacro nnselect-add-prefix (group)
|
(defmacro nnselect-add-prefix (group)
|
||||||
"Ensures that the GROUP has an nnselect prefix."
|
"Ensures that the GROUP has an nnselect prefix."
|
||||||
|
|
@ -504,15 +515,15 @@ If this variable is nil, or if the provided function returns nil,
|
||||||
(list (car artgroup)
|
(list (car artgroup)
|
||||||
(gnus-compress-sequence (sort (cdr artgroup) '<))
|
(gnus-compress-sequence (sort (cdr artgroup) '<))
|
||||||
action marks))
|
action marks))
|
||||||
(numbers-by-group
|
(numbers-by-group range 'range))))
|
||||||
(gnus-uncompress-range range)))))
|
|
||||||
actions)
|
actions)
|
||||||
'car 'cdr)))
|
'car 'cdr)))
|
||||||
|
|
||||||
(deffoo nnselect-request-update-info (group info &optional _server)
|
(deffoo nnselect-request-update-info (group info &optional _server)
|
||||||
(let* ((group (nnselect-add-prefix group))
|
(let* ((group (nnselect-add-prefix group))
|
||||||
(gnus-newsgroup-selection (or gnus-newsgroup-selection
|
(gnus-newsgroup-selection
|
||||||
(nnselect-get-artlist group))))
|
(or gnus-newsgroup-selection (nnselect-get-artlist group)))
|
||||||
|
newmarks)
|
||||||
(gnus-info-set-marks info nil)
|
(gnus-info-set-marks info nil)
|
||||||
(setf (gnus-info-read info) nil)
|
(setf (gnus-info-read info) nil)
|
||||||
(pcase-dolist (`(,artgroup . ,nartids)
|
(pcase-dolist (`(,artgroup . ,nartids)
|
||||||
|
|
@ -520,30 +531,56 @@ If this variable is nil, or if the provided function returns nil,
|
||||||
(number-sequence 1 (nnselect-artlist-length
|
(number-sequence 1 (nnselect-artlist-length
|
||||||
gnus-newsgroup-selection))))
|
gnus-newsgroup-selection))))
|
||||||
(let* ((gnus-newsgroup-active nil)
|
(let* ((gnus-newsgroup-active nil)
|
||||||
(artids (cl-sort nartids '< :key 'car))
|
(artids (cl-sort nartids #'< :key 'car))
|
||||||
(group-info (gnus-get-info artgroup))
|
(group-info (gnus-get-info artgroup))
|
||||||
(marks (gnus-info-marks group-info))
|
(marks (gnus-info-marks group-info))
|
||||||
(unread (gnus-uncompress-sequence
|
(unread (gnus-uncompress-sequence
|
||||||
(gnus-range-difference (gnus-active artgroup)
|
(gnus-range-difference (gnus-active artgroup)
|
||||||
(gnus-info-read group-info)))))
|
(gnus-info-read group-info)))))
|
||||||
(gnus-atomic-progn
|
|
||||||
(setf (gnus-info-read info)
|
(setf (gnus-info-read info)
|
||||||
(gnus-add-to-range
|
(gnus-add-to-range
|
||||||
(gnus-info-read info)
|
(gnus-info-read info)
|
||||||
(delq nil
|
(delq nil (mapcar
|
||||||
(mapcar
|
|
||||||
#'(lambda (art)
|
#'(lambda (art)
|
||||||
(unless (memq (cdr art) unread) (car art)))
|
(unless (memq (cdr art) unread) (car art)))
|
||||||
artids))))
|
artids))))
|
||||||
(pcase-dolist (`(,type . ,range) marks)
|
(pcase-dolist (`(,type . ,mark-list) marks)
|
||||||
(setq range (gnus-uncompress-sequence range))
|
(let ((mark-type (gnus-article-mark-to-type type)) new)
|
||||||
(gnus-add-marked-articles
|
(when
|
||||||
group type
|
(setq new
|
||||||
(delq nil
|
(delq nil
|
||||||
|
(cond
|
||||||
|
((eq mark-type 'tuple)
|
||||||
(mapcar
|
(mapcar
|
||||||
#'(lambda (art)
|
#'(lambda (id)
|
||||||
(when (memq (cdr art) range)
|
(let (mark)
|
||||||
(car art))) artids)))))))
|
(when
|
||||||
|
(setq mark (assq (cdr id) mark-list))
|
||||||
|
(cons (car id) (cdr mark)))))
|
||||||
|
artids))
|
||||||
|
(t
|
||||||
|
(setq mark-list
|
||||||
|
(gnus-uncompress-range mark-list))
|
||||||
|
(mapcar
|
||||||
|
#'(lambda (id)
|
||||||
|
(when (memq (cdr id) mark-list)
|
||||||
|
(car id))) artids)))))
|
||||||
|
(let ((previous (alist-get type newmarks)))
|
||||||
|
(if previous
|
||||||
|
(nconc previous new)
|
||||||
|
(push (cons type new) newmarks))))))))
|
||||||
|
|
||||||
|
;; Clean up the marks: compress lists;
|
||||||
|
(pcase-dolist (`(,type . ,mark-list) newmarks)
|
||||||
|
(let ((mark-type (gnus-article-mark-to-type type)))
|
||||||
|
(unless (eq mark-type 'tuple)
|
||||||
|
(setf (alist-get type newmarks)
|
||||||
|
(gnus-compress-sequence mark-list)))))
|
||||||
|
;; and ensure an unexist key.
|
||||||
|
(unless (assq 'unexist newmarks)
|
||||||
|
(push (cons 'unexist nil) newmarks))
|
||||||
|
|
||||||
|
(gnus-info-set-marks info newmarks)
|
||||||
(gnus-set-active group (cons 1 (nnselect-artlist-length
|
(gnus-set-active group (cons 1 (nnselect-artlist-length
|
||||||
gnus-newsgroup-selection)))))
|
gnus-newsgroup-selection)))))
|
||||||
|
|
||||||
|
|
@ -769,42 +806,61 @@ article came from is also searched."
|
||||||
"Copy mark-lists from GROUP to the originating groups."
|
"Copy mark-lists from GROUP to the originating groups."
|
||||||
(let ((select-unreads (numbers-by-group gnus-newsgroup-unreads))
|
(let ((select-unreads (numbers-by-group gnus-newsgroup-unreads))
|
||||||
(select-reads (numbers-by-group
|
(select-reads (numbers-by-group
|
||||||
(gnus-uncompress-range
|
(gnus-info-read (gnus-get-info group)) 'range))
|
||||||
(gnus-info-read (gnus-get-info group)))))
|
|
||||||
(select-unseen (numbers-by-group gnus-newsgroup-unseen))
|
(select-unseen (numbers-by-group gnus-newsgroup-unseen))
|
||||||
(gnus-newsgroup-active nil)
|
(gnus-newsgroup-active nil) mark-list)
|
||||||
mark-list type-list)
|
;; collect the set of marked article lists categorized by
|
||||||
|
;; originating groups
|
||||||
(pcase-dolist (`(,mark . ,type) gnus-article-mark-lists)
|
(pcase-dolist (`(,mark . ,type) gnus-article-mark-lists)
|
||||||
|
(let (type-list)
|
||||||
(when (setq type-list
|
(when (setq type-list
|
||||||
(symbol-value (intern (format "gnus-newsgroup-%s" mark))))
|
(symbol-value (intern (format "gnus-newsgroup-%s" mark))))
|
||||||
(push (cons type
|
(push (cons
|
||||||
(numbers-by-group
|
type
|
||||||
(gnus-uncompress-range type-list))) mark-list)))
|
(numbers-by-group type-list (gnus-article-mark-to-type type)))
|
||||||
|
mark-list))))
|
||||||
|
;; now work on each originating group one at a time
|
||||||
(pcase-dolist (`(,artgroup . ,artlist)
|
(pcase-dolist (`(,artgroup . ,artlist)
|
||||||
(numbers-by-group gnus-newsgroup-articles))
|
(numbers-by-group gnus-newsgroup-articles))
|
||||||
(let* ((group-info (gnus-get-info artgroup))
|
(let* ((group-info (gnus-get-info artgroup))
|
||||||
(old-unread (gnus-list-of-unread-articles artgroup))
|
(old-unread (gnus-list-of-unread-articles artgroup))
|
||||||
newmarked)
|
newmarked delta-marks)
|
||||||
(when group-info
|
(when group-info
|
||||||
|
;; iterate over mark lists for this group
|
||||||
(pcase-dolist (`(,_mark . ,type) gnus-article-mark-lists)
|
(pcase-dolist (`(,_mark . ,type) gnus-article-mark-lists)
|
||||||
(let ((select-type
|
(let ((list (cdr (assoc artgroup (alist-get type mark-list))))
|
||||||
(sort
|
(mark-type (gnus-article-mark-to-type type)))
|
||||||
(cdr (assoc artgroup (alist-get type mark-list)))
|
|
||||||
'<)) list)
|
|
||||||
(setq list
|
|
||||||
(gnus-uncompress-range
|
|
||||||
(gnus-add-to-range
|
|
||||||
(gnus-remove-from-range
|
|
||||||
(alist-get type (gnus-info-marks group-info))
|
|
||||||
artlist)
|
|
||||||
select-type)))
|
|
||||||
|
|
||||||
(when list
|
;; When the backend can store marks we collect any
|
||||||
;; Get rid of the entries of the articles that have the
|
;; changes. Unlike a normal group the mark lists only
|
||||||
;; default score.
|
;; include marks for articles we retrieved.
|
||||||
(when (and (eq type 'score)
|
(when (and (gnus-check-backend-function
|
||||||
gnus-save-score
|
'request-set-mark artgroup)
|
||||||
list)
|
(not (gnus-article-unpropagatable-p type)))
|
||||||
|
(let* ((old (gnus-list-range-intersection
|
||||||
|
artlist
|
||||||
|
(alist-get type (gnus-info-marks group-info))))
|
||||||
|
(del (gnus-remove-from-range (copy-tree old) list))
|
||||||
|
(add (gnus-remove-from-range (copy-tree list) old)))
|
||||||
|
(when add (push (list add 'add (list type)) delta-marks))
|
||||||
|
(when del
|
||||||
|
;; Don't delete marks from outside the active range.
|
||||||
|
;; This shouldn't happen, but is a sanity check.
|
||||||
|
(setq del (gnus-sorted-range-intersection
|
||||||
|
(gnus-active artgroup) del))
|
||||||
|
(push (list del 'del (list type)) delta-marks))))
|
||||||
|
|
||||||
|
;; Marked sets are of mark-type 'tuple, 'list, or
|
||||||
|
;; 'range. We merge the lists with what is already in
|
||||||
|
;; the original info to get full list of new marks. We
|
||||||
|
;; do this by removing all the articles we retrieved
|
||||||
|
;; from the full list, and then add back in the newly
|
||||||
|
;; marked ones.
|
||||||
|
(cond
|
||||||
|
((eq mark-type 'tuple)
|
||||||
|
;; Get rid of the entries that have the default
|
||||||
|
;; score.
|
||||||
|
(when (and list (eq type 'score) gnus-save-score)
|
||||||
(let* ((arts list)
|
(let* ((arts list)
|
||||||
(prev (cons nil list))
|
(prev (cons nil list))
|
||||||
(all prev))
|
(all prev))
|
||||||
|
|
@ -814,30 +870,41 @@ article came from is also searched."
|
||||||
(setcdr prev (cdr arts))
|
(setcdr prev (cdr arts))
|
||||||
(setq prev arts))
|
(setq prev arts))
|
||||||
(setq arts (cdr arts)))
|
(setq arts (cdr arts)))
|
||||||
(setq list (cdr all)))))
|
(setq list (cdr all))))
|
||||||
|
;; now merge with the original list and sort just to
|
||||||
(when (or (eq (gnus-article-mark-to-type type) 'list)
|
;; make sure
|
||||||
(eq (gnus-article-mark-to-type type) 'range))
|
|
||||||
(setq list
|
(setq list
|
||||||
(gnus-compress-sequence (sort list '<) t)))
|
(sort (map-merge
|
||||||
|
'list list
|
||||||
|
(alist-get type (gnus-info-marks group-info)))
|
||||||
|
(lambda (elt1 elt2)
|
||||||
|
(< (car elt1) (car elt2))))))
|
||||||
|
(t
|
||||||
|
(setq list
|
||||||
|
(gnus-compress-sequence
|
||||||
|
(gnus-sorted-union
|
||||||
|
(gnus-sorted-difference
|
||||||
|
(gnus-uncompress-sequence
|
||||||
|
(alist-get type (gnus-info-marks group-info)))
|
||||||
|
artlist)
|
||||||
|
(sort list #'<)) t)))
|
||||||
|
|
||||||
;; When exiting the group, everything that's previously been
|
;; When exiting the group, everything that's previously been
|
||||||
;; unseen is now seen.
|
;; unseen is now seen.
|
||||||
(when (eq type 'seen)
|
(when (eq type 'seen)
|
||||||
(setq list (gnus-range-add
|
(setq list (gnus-range-add
|
||||||
list (cdr (assoc artgroup select-unseen)))))
|
list (cdr (assoc artgroup select-unseen))))))
|
||||||
|
|
||||||
(when (or list (eq type 'unexist))
|
(when (or list (eq type 'unexist))
|
||||||
(push (cons type list) newmarked))))
|
(push (cons type list) newmarked)))) ;; end of mark-type loop
|
||||||
|
|
||||||
|
(when delta-marks
|
||||||
|
(unless (gnus-check-group artgroup)
|
||||||
|
(error "Can't open server for %s" artgroup))
|
||||||
|
(gnus-request-set-mark artgroup delta-marks))
|
||||||
|
|
||||||
(gnus-atomic-progn
|
(gnus-atomic-progn
|
||||||
;; Enter these new marks into the info of the group.
|
(gnus-info-set-marks group-info newmarked)
|
||||||
(if (nthcdr 3 group-info)
|
|
||||||
(setcar (nthcdr 3 group-info) newmarked)
|
|
||||||
;; Add the marks lists to the end of the info.
|
|
||||||
(when newmarked
|
|
||||||
(setcdr (nthcdr 2 group-info) (list newmarked))))
|
|
||||||
|
|
||||||
;; Cut off the end of the info if there's nothing else there.
|
;; Cut off the end of the info if there's nothing else there.
|
||||||
(let ((i 5))
|
(let ((i 5))
|
||||||
(while (and (> i 2)
|
(while (and (> i 2)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue