diff options
| author | Andrew G Cohen | 2020-09-23 19:47:15 +0800 |
|---|---|---|
| committer | Andrew G Cohen | 2020-09-23 19:52:38 +0800 |
| commit | 6037051f49ab5f96b406461490dba56faa2a5f35 (patch) | |
| tree | 0f579b0aeebbf5996b8797dbfa3536b8104ed936 | |
| parent | e4831151c2b746564319018105a17fbde4b553c6 (diff) | |
| download | emacs-6037051f49ab5f96b406461490dba56faa2a5f35.tar.gz emacs-6037051f49ab5f96b406461490dba56faa2a5f35.zip | |
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.
| -rw-r--r-- | lisp/gnus/nnselect.el | 217 |
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) |