From: Stefan Monnier Date: Fri, 17 May 2019 04:09:16 +0000 (-0400) Subject: * lisp/gnus: Remove assumptions about mail-header being a vector X-Git-Tag: emacs-27.0.90~2855 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=a93e672e279adc45782254a66520471c336ed4ac;p=emacs.git * lisp/gnus: Remove assumptions about mail-header being a vector Use `mail-header-p` and `make-full-mail-header` instead of `vectorp` and `vector`, respectively. * lisp/gnus/message.el (message-cite-original-1, message-reply) (message-followup): * lisp/gnus/gnus-sum.el (gnus-get-newsgroup-headers): Use make-full-mail-header instead of `vector`. (gnus--dummy-mail-header): New const, using make-full-mail-header. (gnus-update-summary-mark-positions): Use it instead of an immediate vector. (gnus-set-mode-line, gnus-summary-article-pseudo-p) (gnus-summary-article-subject, gnus-summary-insert-subject) (gnus-summary-find-subject, gnus-summary-goto-subject) (gnus-summary-limit-to-age, gnus-summary-find-matching) (gnus-summary-mark-article-as-unread, gnus-summary-mark-article) (gnus-summary-save-article): * lisp/gnus/gnus.el (gnus-news-group-p): Use mail-header-p instead of vectorp. --- diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index 00f0de61d7f..f761fdb7945 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el @@ -3267,7 +3267,7 @@ The following commands are available: (defun gnus-summary-article-pseudo-p (article) "Say whether this article is a pseudo article or not." - (not (vectorp (gnus-data-header (gnus-data-find article))))) + (not (mail-header-p (gnus-data-header (gnus-data-find article))))) (defmacro gnus-summary-article-sparse-p (article) "Say whether this article is a sparse article or not." @@ -3343,7 +3343,7 @@ article number." '(gnus-data-header (assq (gnus-summary-article-number) gnus-newsgroup-data))))) (and headers - (vectorp headers) + (mail-header-p headers) (mail-header-subject headers)))) (defmacro gnus-summary-article-score (&optional number) @@ -3600,6 +3600,9 @@ buffer that was in action when the last article was fetched." t (not (cdr (gnus-data-find-list article))))) +(defconst gnus--dummy-mail-header + (make-full-mail-header 0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil)) + (defun gnus-make-thread-indent-array (&optional n) (when (or n (progn (setq n 200) nil) @@ -3628,10 +3631,9 @@ buffer that was in action when the last article was fetched." (gnus-undownloaded-mark ?Z) (gnus-summary-line-format-spec spec) (gnus-newsgroup-downloadable '(0)) - (header [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil]) case-fold-search ignores) ;; Here, all marks are bound to Z. - (gnus-summary-insert-line header + (gnus-summary-insert-line gnus--dummy-mail-header 0 nil t gnus-tmp-unread t nil "" nil 1) (goto-char (point-min)) ;; Memorize the positions of the same characters as dummy marks. @@ -3645,7 +3647,7 @@ buffer that was in action when the last article was fetched." gnus-score-below-mark ?C gnus-score-over-mark ?C gnus-undownloaded-mark ?D) - (gnus-summary-insert-line header + (gnus-summary-insert-line gnus--dummy-mail-header 0 nil t gnus-tmp-unread t nil "" nil 1) ;; Ignore characters which aren't dummy marks. (dolist (p ignores) @@ -6219,7 +6221,7 @@ If WHERE is `summary', the summary mode line format will be used." gnus-tmp-unselected)))) (gnus-tmp-subject (if (and gnus-current-headers - (vectorp gnus-current-headers)) + (mail-header-p gnus-current-headers)) (gnus-mode-string-quote (mail-header-subject gnus-current-headers)) "")) @@ -6436,7 +6438,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." ;; doesn't always go hand in hand. (setq header - (vector + (make-full-mail-header ;; Number. (prog1 (setq number (read cur)) @@ -6649,7 +6651,7 @@ If USE-OLD-HEADER is non-nil, then OLD-HEADER should be a header, and OLD-HEADER will be used when the summary line is inserted, too, instead of trying to fetch new headers." (let* ((line (and (numberp old-header) old-header)) - (old-header (and (vectorp old-header) old-header)) + (old-header (and (mail-header-p old-header) old-header)) (header (cond ((and old-header use-old-header) old-header) ((and (numberp id) @@ -6887,7 +6889,7 @@ If EXCLUDE-GROUP, do not go to this group." (while arts (and (or (not unread) (gnus-data-unread-p (car arts))) - (vectorp (gnus-data-header (car arts))) + (mail-header-p (gnus-data-header (car arts))) (gnus-subject-equal simp-subject (mail-header-subject (gnus-data-header (car arts))) t) (setq result (car arts) @@ -7724,7 +7726,7 @@ If FORCE, also allow jumping to articles not currently shown." force (gnus-summary-insert-subject article - (if (or (numberp force) (vectorp force)) force) + (if (or (numberp force) (mail-header-p force)) force) t) (setq data (gnus-data-find article))) (goto-char b) @@ -8469,7 +8471,7 @@ articles that are younger than AGE days." (cutoff (days-to-time age)) articles d date is-younger) (while (setq d (pop data)) - (when (and (vectorp (gnus-data-header d)) + (when (and (mail-header-p (gnus-data-header d)) (setq date (mail-header-date (gnus-data-header d)))) (setq is-younger (time-less-p (time-since (gnus-date-get-time date)) @@ -9614,7 +9616,7 @@ not match REGEXP on HEADER." (gnus-data-list backward)))) (when (and (or (not unread) ; We want all articles... (gnus-data-unread-p d)) ; Or just unreads. - (vectorp (gnus-data-header d)) ; It's not a pseudo. + (mail-header-p (gnus-data-header d)) ; It's not a pseudo. (if not-matching (not (string-match regexp @@ -11151,7 +11153,7 @@ If NO-EXPIRE, auto-expiry will be inhibited." ;; See whether the article is to be put in the cache. (and gnus-use-cache - (vectorp (gnus-summary-article-header article)) + (mail-header-p (gnus-summary-article-header article)) (save-excursion (gnus-cache-possibly-enter-article gnus-newsgroup-name article @@ -11198,7 +11200,7 @@ If NO-EXPIRE, auto-expiry will be inhibited." ;; See whether the article is to be put in the cache. (and gnus-use-cache (not (= mark gnus-canceled-mark)) - (vectorp (gnus-summary-article-header article)) + (mail-header-p (gnus-summary-article-header article)) (save-excursion (gnus-cache-possibly-enter-article gnus-newsgroup-name article @@ -12147,7 +12149,7 @@ performed." header file) (dolist (article articles) (setq header (gnus-summary-article-header article)) - (if (not (vectorp header)) + (if (not (mail-header-p header)) ;; This is a pseudo-article. (if (assq 'name header) (gnus-copy-file (cdr (assq 'name header))) diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el index 3d7c37eac89..7538274e158 100644 --- a/lisp/gnus/gnus.el +++ b/lisp/gnus/gnus.el @@ -3143,7 +3143,7 @@ that that variable is buffer-local to the summary buffers." t) ;is news of course. ((not (gnus-member-of-valid 'post-mail group)) ;Non-combined. nil) ;must be mail then. - ((vectorp article) ;Has header info. + ((mail-header-p article) ;Has header info. (eq (gnus-request-type group (mail-header-id article)) 'news)) ((null article) ;Hasn't header info (eq (gnus-request-type group) 'news)) ;(unknown ==> mail) diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el index edfe1a39f3d..8b72ef88aba 100644 --- a/lisp/gnus/message.el +++ b/lisp/gnus/message.el @@ -3819,13 +3819,14 @@ This function uses `mail-citation-hook' if that is non-nil." (narrow-to-region start end) (message-narrow-to-head-1) (setq x-no-archive (message-fetch-field "x-no-archive")) - (vector 0 - (or (message-fetch-field "subject") "none") - (or (message-fetch-field "from") "nobody") - (message-fetch-field "date") - (message-fetch-field "message-id" t) - (message-fetch-field "references") - 0 0 "")))) + (make-full-mail-header + 0 + (or (message-fetch-field "subject") "none") + (or (message-fetch-field "from") "nobody") + (message-fetch-field "date") + (message-fetch-field "message-id" t) + (message-fetch-field "references") + 0 0 "")))) (mml-quote-region start end) (when strip-signature ;; Allow undoing. @@ -6977,8 +6978,8 @@ specified by FUNCTIONS, if non-nil, or by the variable (if wide to-address nil)) switch-function)) (setq message-reply-headers - (vector 0 (cdr (assq 'Subject headers)) - from date message-id references 0 0 "")) + (make-full-mail-header 0 (cdr (assq 'Subject headers)) + from date message-id references 0 0 "")) (message-setup headers cur)))) ;;;###autoload @@ -7035,7 +7036,8 @@ If TO-NEWSGROUPS, use that as the new Newsgroups line." (message-pop-to-buffer (message-buffer-name "followup" from newsgroups)) (setq message-reply-headers - (vector 0 subject from date message-id references 0 0 "")) + (make-full-mail-header + 0 subject from date message-id references 0 0 "")) (message-setup `((Subject . ,subject) diff --git a/lisp/gnus/nnheader.el b/lisp/gnus/nnheader.el index e138f141c69..d30a7399493 100644 --- a/lisp/gnus/nnheader.el +++ b/lisp/gnus/nnheader.el @@ -136,6 +136,7 @@ on your system, you could say something like: ;; (That next-to-last entry is defined as "misc" in the NOV format, ;; but Gnus uses it for xrefs.) +(defalias 'mail-header-p #'vectorp) ;For lack of tag, it's all we have. (cl-defstruct (mail-header (:type vector) (:constructor nil) diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el index c80bbf61875..25f3413fcd5 100644 --- a/lisp/gnus/nnvirtual.el +++ b/lisp/gnus/nnvirtual.el @@ -491,9 +491,9 @@ If UPDATE-P is not nil, call gnus-group-update-group on the components." -;;; This is currently O(kn^2) to merge n lists of length k. -;;; You could do it in O(knlogn), but we have a small n, and the -;;; overhead of the other approach is probably greater. +;; This is currently O(kn^2) to merge n lists of length k. +;; You could do it in O(knlogn), but we have a small n, and the +;; overhead of the other approach is probably greater. (defun nnvirtual-merge-sorted-lists (&rest lists) "Merge many sorted lists of numbers." (if (null (cdr lists)) @@ -501,68 +501,68 @@ If UPDATE-P is not nil, call gnus-group-update-group on the components." (sort (apply 'nconc lists) '<))) -;;; We map between virtual articles and real articles in a manner -;;; which keeps the size of the virtual active list the same as the -;;; sum of the component active lists. - -;;; To achieve fair mixing of the groups, the last article in each of -;;; N component groups will be in the last N articles in the virtual -;;; group. - -;;; If you have 3 components A, B and C, with articles 1-8, 1-5, and -;;; 6-7 respectively, then the virtual article numbers look like: -;;; -;;; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -;;; A1 A2 A3 A4 B1 A5 B2 A6 B3 A7 B4 C6 A8 B5 C7 - -;;; To compute these mappings we generate a couple tables and then -;;; do some fast operations on them. Tables for the example above: -;;; -;;; Offsets - [(A 0) (B -3) (C -1)] -;;; -;;; a b c d e -;;; Mapping - ([ 3 0 1 3 0 ] -;;; [ 6 3 2 9 3 ] -;;; [ 8 6 3 15 9 ]) -;;; -;;; (note column 'e' is different in real algorithm, which is slightly -;;; different than described here, but this gives you the methodology.) -;;; -;;; The basic idea is this, when going from component->virtual, apply -;;; the appropriate offset to the article number. Then search the first -;;; column of the table for a row where 'a' is less than or equal to the -;;; modified number. You can see that only group A can therefore go to -;;; the first row, groups A and B to the second, and all to the last. -;;; The third column of the table is telling us the number of groups -;;; which might be able to reach that row (it might increase by more than -;;; 1 if several groups have the same size). -;;; Then column 'b' provides an additional offset you apply when you have -;;; found the correct row. You then multiply by 'c' and add on the groups -;;; _position_ in the offset table. The basic idea here is that on -;;; any given row we are going to map back and forth using X'=X*c+Y and -;;; X=(X'/c), Y=(X' mod c). Then once you've done this transformation, -;;; you apply a final offset from column 'e' to give the virtual article. -;;; -;;; Going the other direction, you instead search on column 'd' instead -;;; of 'a', and apply everything in reverse order. - -;;; Convert component -> virtual: -;;; set num = num - Offset(group) -;;; find first row in Mapping where num <= 'a' -;;; num = (num-'b')*c + Position(group) + 'e' - -;;; Convert virtual -> component: -;;; find first row in Mapping where num <= 'd' -;;; num = num - 'e' -;;; group_pos = num mod 'c' -;;; num = (num / 'c') + 'b' + Offset(group_pos) - -;;; Easy no? :) -;;; -;;; Well actually, you need to keep column e offset smaller by the 'c' -;;; column for that line, and always add 1 more when going from -;;; component -> virtual. Otherwise you run into a problem with -;;; unique reverse mapping. +;; We map between virtual articles and real articles in a manner +;; which keeps the size of the virtual active list the same as the +;; sum of the component active lists. + +;; To achieve fair mixing of the groups, the last article in each of +;; N component groups will be in the last N articles in the virtual +;; group. + +;; If you have 3 components A, B and C, with articles 1-8, 1-5, and +;; 6-7 respectively, then the virtual article numbers look like: +;; +;; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +;; A1 A2 A3 A4 B1 A5 B2 A6 B3 A7 B4 C6 A8 B5 C7 + +;; To compute these mappings we generate a couple tables and then +;; do some fast operations on them. Tables for the example above: +;; +;; Offsets - [(A 0) (B -3) (C -1)] +;; +;; a b c d e +;; Mapping - ([ 3 0 1 3 0 ] +;; [ 6 3 2 9 3 ] +;; [ 8 6 3 15 9 ]) +;; +;; (note column 'e' is different in real algorithm, which is slightly +;; different than described here, but this gives you the methodology.) +;; +;; The basic idea is this, when going from component->virtual, apply +;; the appropriate offset to the article number. Then search the first +;; column of the table for a row where 'a' is less than or equal to the +;; modified number. You can see that only group A can therefore go to +;; the first row, groups A and B to the second, and all to the last. +;; The third column of the table is telling us the number of groups +;; which might be able to reach that row (it might increase by more than +;; 1 if several groups have the same size). +;; Then column 'b' provides an additional offset you apply when you have +;; found the correct row. You then multiply by 'c' and add on the groups +;; _position_ in the offset table. The basic idea here is that on +;; any given row we are going to map back and forth using X'=X*c+Y and +;; X=(X'/c), Y=(X' mod c). Then once you've done this transformation, +;; you apply a final offset from column 'e' to give the virtual article. +;; +;; Going the other direction, you instead search on column 'd' instead +;; of 'a', and apply everything in reverse order. + +;; Convert component -> virtual: +;; set num = num - Offset(group) +;; find first row in Mapping where num <= 'a' +;; num = (num-'b')*c + Position(group) + 'e' + +;; Convert virtual -> component: +;; find first row in Mapping where num <= 'd' +;; num = num - 'e' +;; group_pos = num mod 'c' +;; num = (num / 'c') + 'b' + Offset(group_pos) + +;; Easy no? :) +;; +;; Well actually, you need to keep column e offset smaller by the 'c' +;; column for that line, and always add 1 more when going from +;; component -> virtual. Otherwise you run into a problem with +;; unique reverse mapping. (defun nnvirtual-map-article (article) "Return a cons of the component group and article corresponding to the given virtual ARTICLE."