aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/gnus/nnselect.el217
1 files changed, 142 insertions, 75 deletions
diff --git a/lisp/gnus/nnselect.el b/lisp/gnus/nnselect.el
index c6f2ffae9c6..8cd658100fb 100644
--- a/lisp/gnus/nnselect.el
+++ b/lisp/gnus/nnselect.el
@@ -203,11 +203,22 @@ as `(keyfunc member)' and the corresponding element is just
203 (nnselect-categorize ,articles 'nnselect-article-group 203 (nnselect-categorize ,articles 'nnselect-article-group
204 'nnselect-article-id))) 204 'nnselect-article-id)))
205 205
206(define-inline numbers-by-group (articles) 206(define-inline numbers-by-group (articles &optional type)
207 (inline-quote 207 (inline-quote
208 (nnselect-categorize 208 (cond
209 ,articles 'nnselect-article-group 'nnselect-article-number))) 209 ((eq ,type 'range)
210 210 (nnselect-categorize (gnus-uncompress-range ,articles)
211 'nnselect-article-group 'nnselect-article-number))
212 ((eq ,type 'tuple)
213 (nnselect-categorize ,articles
214 #'(lambda (elem)
215 (nnselect-article-group (car elem)))
216 #'(lambda (elem)
217 (cons (nnselect-article-number
218 (car elem)) (cdr elem)))))
219 (t
220 (nnselect-categorize ,articles
221 'nnselect-article-group 'nnselect-article-number)))))
211 222
212(defmacro nnselect-add-prefix (group) 223(defmacro nnselect-add-prefix (group)
213 "Ensures that the GROUP has an nnselect prefix." 224 "Ensures that the GROUP has an nnselect prefix."
@@ -504,15 +515,15 @@ If this variable is nil, or if the provided function returns nil,
504 (list (car artgroup) 515 (list (car artgroup)
505 (gnus-compress-sequence (sort (cdr artgroup) '<)) 516 (gnus-compress-sequence (sort (cdr artgroup) '<))
506 action marks)) 517 action marks))
507 (numbers-by-group 518 (numbers-by-group range 'range))))
508 (gnus-uncompress-range range)))))
509 actions) 519 actions)
510 'car 'cdr))) 520 'car 'cdr)))
511 521
512(deffoo nnselect-request-update-info (group info &optional _server) 522(deffoo nnselect-request-update-info (group info &optional _server)
513 (let* ((group (nnselect-add-prefix group)) 523 (let* ((group (nnselect-add-prefix group))
514 (gnus-newsgroup-selection (or gnus-newsgroup-selection 524 (gnus-newsgroup-selection
515 (nnselect-get-artlist group)))) 525 (or gnus-newsgroup-selection (nnselect-get-artlist group)))
526 newmarks)
516 (gnus-info-set-marks info nil) 527 (gnus-info-set-marks info nil)
517 (setf (gnus-info-read info) nil) 528 (setf (gnus-info-read info) nil)
518 (pcase-dolist (`(,artgroup . ,nartids) 529 (pcase-dolist (`(,artgroup . ,nartids)
@@ -520,30 +531,56 @@ If this variable is nil, or if the provided function returns nil,
520 (number-sequence 1 (nnselect-artlist-length 531 (number-sequence 1 (nnselect-artlist-length
521 gnus-newsgroup-selection)))) 532 gnus-newsgroup-selection))))
522 (let* ((gnus-newsgroup-active nil) 533 (let* ((gnus-newsgroup-active nil)
523 (artids (cl-sort nartids '< :key 'car)) 534 (artids (cl-sort nartids #'< :key 'car))
524 (group-info (gnus-get-info artgroup)) 535 (group-info (gnus-get-info artgroup))
525 (marks (gnus-info-marks group-info)) 536 (marks (gnus-info-marks group-info))
526 (unread (gnus-uncompress-sequence 537 (unread (gnus-uncompress-sequence
527 (gnus-range-difference (gnus-active artgroup) 538 (gnus-range-difference (gnus-active artgroup)
528 (gnus-info-read group-info))))) 539 (gnus-info-read group-info)))))
529 (gnus-atomic-progn 540 (setf (gnus-info-read info)
530 (setf (gnus-info-read info) 541 (gnus-add-to-range
531 (gnus-add-to-range 542 (gnus-info-read info)
532 (gnus-info-read info) 543 (delq nil (mapcar
533 (delq nil 544 #'(lambda (art)
534 (mapcar 545 (unless (memq (cdr art) unread) (car art)))
535 #'(lambda (art) 546 artids))))
536 (unless (memq (cdr art) unread) (car art))) 547 (pcase-dolist (`(,type . ,mark-list) marks)
537 artids)))) 548 (let ((mark-type (gnus-article-mark-to-type type)) new)
538 (pcase-dolist (`(,type . ,range) marks) 549 (when
539 (setq range (gnus-uncompress-sequence range)) 550 (setq new
540 (gnus-add-marked-articles 551 (delq nil
541 group type 552 (cond
542 (delq nil 553 ((eq mark-type 'tuple)
543 (mapcar 554 (mapcar
544 #'(lambda (art) 555 #'(lambda (id)
545 (when (memq (cdr art) range) 556 (let (mark)
546 (car art))) artids))))))) 557 (when
558 (setq mark (assq (cdr id) mark-list))
559 (cons (car id) (cdr mark)))))
560 artids))
561 (t
562 (setq mark-list
563 (gnus-uncompress-range mark-list))
564 (mapcar
565 #'(lambda (id)
566 (when (memq (cdr id) mark-list)
567 (car id))) artids)))))
568 (let ((previous (alist-get type newmarks)))
569 (if previous
570 (nconc previous new)
571 (push (cons type new) newmarks))))))))
572
573 ;; Clean up the marks: compress lists;
574 (pcase-dolist (`(,type . ,mark-list) newmarks)
575 (let ((mark-type (gnus-article-mark-to-type type)))
576 (unless (eq mark-type 'tuple)
577 (setf (alist-get type newmarks)
578 (gnus-compress-sequence mark-list)))))
579 ;; and ensure an unexist key.
580 (unless (assq 'unexist newmarks)
581 (push (cons 'unexist nil) newmarks))
582
583 (gnus-info-set-marks info newmarks)
547 (gnus-set-active group (cons 1 (nnselect-artlist-length 584 (gnus-set-active group (cons 1 (nnselect-artlist-length
548 gnus-newsgroup-selection))))) 585 gnus-newsgroup-selection)))))
549 586
@@ -769,42 +806,61 @@ article came from is also searched."
769 "Copy mark-lists from GROUP to the originating groups." 806 "Copy mark-lists from GROUP to the originating groups."
770 (let ((select-unreads (numbers-by-group gnus-newsgroup-unreads)) 807 (let ((select-unreads (numbers-by-group gnus-newsgroup-unreads))
771 (select-reads (numbers-by-group 808 (select-reads (numbers-by-group
772 (gnus-uncompress-range 809 (gnus-info-read (gnus-get-info group)) 'range))
773 (gnus-info-read (gnus-get-info group)))))
774 (select-unseen (numbers-by-group gnus-newsgroup-unseen)) 810 (select-unseen (numbers-by-group gnus-newsgroup-unseen))
775 (gnus-newsgroup-active nil) 811 (gnus-newsgroup-active nil) mark-list)
776 mark-list type-list) 812 ;; collect the set of marked article lists categorized by
813 ;; originating groups
777 (pcase-dolist (`(,mark . ,type) gnus-article-mark-lists) 814 (pcase-dolist (`(,mark . ,type) gnus-article-mark-lists)
778 (when (setq type-list 815 (let (type-list)
779 (symbol-value (intern (format "gnus-newsgroup-%s" mark)))) 816 (when (setq type-list
780 (push (cons type 817 (symbol-value (intern (format "gnus-newsgroup-%s" mark))))
781 (numbers-by-group 818 (push (cons
782 (gnus-uncompress-range type-list))) mark-list))) 819 type
820 (numbers-by-group type-list (gnus-article-mark-to-type type)))
821 mark-list))))
822 ;; now work on each originating group one at a time
783 (pcase-dolist (`(,artgroup . ,artlist) 823 (pcase-dolist (`(,artgroup . ,artlist)
784 (numbers-by-group gnus-newsgroup-articles)) 824 (numbers-by-group gnus-newsgroup-articles))
785 (let* ((group-info (gnus-get-info artgroup)) 825 (let* ((group-info (gnus-get-info artgroup))
786 (old-unread (gnus-list-of-unread-articles artgroup)) 826 (old-unread (gnus-list-of-unread-articles artgroup))
787 newmarked) 827 newmarked delta-marks)
788 (when group-info 828 (when group-info
829 ;; iterate over mark lists for this group
789 (pcase-dolist (`(,_mark . ,type) gnus-article-mark-lists) 830 (pcase-dolist (`(,_mark . ,type) gnus-article-mark-lists)
790 (let ((select-type 831 (let ((list (cdr (assoc artgroup (alist-get type mark-list))))
791 (sort 832 (mark-type (gnus-article-mark-to-type type)))
792 (cdr (assoc artgroup (alist-get type mark-list))) 833
793 '<)) list) 834 ;; When the backend can store marks we collect any
794 (setq list 835 ;; changes. Unlike a normal group the mark lists only
795 (gnus-uncompress-range 836 ;; include marks for articles we retrieved.
796 (gnus-add-to-range 837 (when (and (gnus-check-backend-function
797 (gnus-remove-from-range 838 'request-set-mark artgroup)
798 (alist-get type (gnus-info-marks group-info)) 839 (not (gnus-article-unpropagatable-p type)))
799 artlist) 840 (let* ((old (gnus-list-range-intersection
800 select-type))) 841 artlist
801 842 (alist-get type (gnus-info-marks group-info))))
802 (when list 843 (del (gnus-remove-from-range (copy-tree old) list))
803 ;; Get rid of the entries of the articles that have the 844 (add (gnus-remove-from-range (copy-tree list) old)))
804 ;; default score. 845 (when add (push (list add 'add (list type)) delta-marks))
805 (when (and (eq type 'score) 846 (when del
806 gnus-save-score 847 ;; Don't delete marks from outside the active range.
807 list) 848 ;; This shouldn't happen, but is a sanity check.
849 (setq del (gnus-sorted-range-intersection
850 (gnus-active artgroup) del))
851 (push (list del 'del (list type)) delta-marks))))
852
853 ;; Marked sets are of mark-type 'tuple, 'list, or
854 ;; 'range. We merge the lists with what is already in
855 ;; the original info to get full list of new marks. We
856 ;; do this by removing all the articles we retrieved
857 ;; from the full list, and then add back in the newly
858 ;; marked ones.
859 (cond
860 ((eq mark-type 'tuple)
861 ;; Get rid of the entries that have the default
862 ;; score.
863 (when (and list (eq type 'score) gnus-save-score)
808 (let* ((arts list) 864 (let* ((arts list)
809 (prev (cons nil list)) 865 (prev (cons nil list))
810 (all prev)) 866 (all prev))
@@ -814,30 +870,41 @@ article came from is also searched."
814 (setcdr prev (cdr arts)) 870 (setcdr prev (cdr arts))
815 (setq prev arts)) 871 (setq prev arts))
816 (setq arts (cdr arts))) 872 (setq arts (cdr arts)))
817 (setq list (cdr all))))) 873 (setq list (cdr all))))
818 874 ;; now merge with the original list and sort just to
819 (when (or (eq (gnus-article-mark-to-type type) 'list) 875 ;; make sure
820 (eq (gnus-article-mark-to-type type) 'range))
821 (setq list 876 (setq list
822 (gnus-compress-sequence (sort list '<) t))) 877 (sort (map-merge
823 878 'list list
824 ;; When exiting the group, everything that's previously been 879 (alist-get type (gnus-info-marks group-info)))
825 ;; unseen is now seen. 880 (lambda (elt1 elt2)
826 (when (eq type 'seen) 881 (< (car elt1) (car elt2))))))
827 (setq list (gnus-range-add 882 (t
828 list (cdr (assoc artgroup select-unseen))))) 883 (setq list
884 (gnus-compress-sequence
885 (gnus-sorted-union
886 (gnus-sorted-difference
887 (gnus-uncompress-sequence
888 (alist-get type (gnus-info-marks group-info)))
889 artlist)
890 (sort list #'<)) t)))
891
892 ;; When exiting the group, everything that's previously been
893 ;; unseen is now seen.
894 (when (eq type 'seen)
895 (setq list (gnus-range-add
896 list (cdr (assoc artgroup select-unseen))))))
829 897
830 (when (or list (eq type 'unexist)) 898 (when (or list (eq type 'unexist))
831 (push (cons type list) newmarked)))) 899 (push (cons type list) newmarked)))) ;; end of mark-type loop
832 900
833 (gnus-atomic-progn 901 (when delta-marks
834 ;; Enter these new marks into the info of the group. 902 (unless (gnus-check-group artgroup)
835 (if (nthcdr 3 group-info) 903 (error "Can't open server for %s" artgroup))
836 (setcar (nthcdr 3 group-info) newmarked) 904 (gnus-request-set-mark artgroup delta-marks))
837 ;; Add the marks lists to the end of the info.
838 (when newmarked
839 (setcdr (nthcdr 2 group-info) (list newmarked))))
840 905
906 (gnus-atomic-progn
907 (gnus-info-set-marks group-info newmarked)
841 ;; Cut off the end of the info if there's nothing else there. 908 ;; Cut off the end of the info if there's nothing else there.
842 (let ((i 5)) 909 (let ((i 5))
843 (while (and (> i 2) 910 (while (and (> i 2)