aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/mail/rmailsort.el166
1 files changed, 94 insertions, 72 deletions
diff --git a/lisp/mail/rmailsort.el b/lisp/mail/rmailsort.el
index 68398b06fc8..cfc93985719 100644
--- a/lisp/mail/rmailsort.el
+++ b/lisp/mail/rmailsort.el
@@ -1,7 +1,7 @@
1;;; rmailsort.el --- Rmail: sort messages 1;;; rmailsort.el --- Rmail: sort messages
2 2
3;; Copyright (C) 1990, 1993, 1994, 2001, 2002, 2003, 2004, 3;; Copyright (C) 1990, 1993, 1994, 2001, 2002, 2003, 2004, 2005, 2006,
4;; 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 4;; 2007, 2008, 2009 Free Software Foundation, Inc.
5 5
6;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp> 6;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp>
7;; Maintainer: FSF 7;; Maintainer: FSF
@@ -24,78 +24,82 @@
24 24
25;;; Commentary: 25;;; Commentary:
26 26
27;; Functions for sorting messages in an Rmail buffer.
28
27;;; Code: 29;;; Code:
28 30
29(require 'rmail) 31(require 'rmail)
30 32
31;; Sorting messages in Rmail buffer
32
33;;;###autoload 33;;;###autoload
34(defun rmail-sort-by-date (reverse) 34(defun rmail-sort-by-date (reverse)
35 "Sort messages of current Rmail file by date. 35 "Sort messages of current Rmail buffer by \"Date\" header.
36If prefix argument REVERSE is non-nil, sort them in reverse order." 36If prefix argument REVERSE is non-nil, sorts in reverse order."
37 (interactive "P") 37 (interactive "P")
38 (rmail-sort-messages reverse 38 (rmail-sort-messages reverse
39 (function 39 (lambda (msg)
40 (lambda (msg) 40 (rmail-make-date-sortable
41 (rmail-make-date-sortable 41 (rmail-get-header "Date" msg)))))
42 (rmail-get-header "Date" msg))))))
43 42
44;;;###autoload 43;;;###autoload
45(defun rmail-sort-by-subject (reverse) 44(defun rmail-sort-by-subject (reverse)
46 "Sort messages of current Rmail file by subject. 45 "Sort messages of current Rmail buffer by \"Subject\" header.
47If prefix argument REVERSE is non-nil, sort them in reverse order." 46Ignores any \"Re: \" prefix. If prefix argument REVERSE is
47non-nil, sorts in reverse order."
48 ;; Note this is a case-sensitive sort.
48 (interactive "P") 49 (interactive "P")
49 (rmail-sort-messages reverse 50 (rmail-sort-messages reverse
50 (function 51 (lambda (msg)
51 (lambda (msg) 52 (let ((key (or (rmail-get-header "Subject" msg) ""))
52 (let ((key (or (rmail-get-header "Subject" msg) "")) 53 (case-fold-search t))
53 (case-fold-search t)) 54 ;; Remove `Re:'
54 ;; Remove `Re:' 55 (if (string-match "^\\(re:[ \t]*\\)*" key)
55 (if (string-match "^\\(re:[ \t]*\\)*" key) 56 (substring key (match-end 0))
56 (substring key (match-end 0)) 57 key)))))
57 key))))))
58 58
59;;;###autoload 59;;;###autoload
60(defun rmail-sort-by-author (reverse) 60(defun rmail-sort-by-author (reverse)
61 "Sort messages of current Rmail file by author. 61 "Sort messages of current Rmail buffer by author.
62If prefix argument REVERSE is non-nil, sort them in reverse order." 62This uses either the \"From\" or \"Sender\" header, downcased.
63If prefix argument REVERSE is non-nil, sorts in reverse order."
63 (interactive "P") 64 (interactive "P")
64 (rmail-sort-messages reverse 65 (rmail-sort-messages reverse
65 (function 66 (lambda (msg)
66 (lambda (msg) 67 (downcase ; canonical name
67 (downcase ;Canonical name 68 (mail-strip-quoted-names
68 (mail-strip-quoted-names 69 (or (rmail-get-header "From" msg)
69 (or (rmail-get-header "From" msg) 70 (rmail-get-header "Sender" msg) ""))))))
70 (rmail-get-header "Sender" msg) "")))))))
71 71
72;;;###autoload 72;;;###autoload
73(defun rmail-sort-by-recipient (reverse) 73(defun rmail-sort-by-recipient (reverse)
74 "Sort messages of current Rmail file by recipient. 74 "Sort messages of current Rmail buffer by recipient.
75If prefix argument REVERSE is non-nil, sort them in reverse order." 75This uses either the \"To\" or \"Apparently-To\" header, downcased.
76If prefix argument REVERSE is non-nil, sorts in reverse order."
76 (interactive "P") 77 (interactive "P")
77 (rmail-sort-messages reverse 78 (rmail-sort-messages reverse
78 (function 79 (lambda (msg)
79 (lambda (msg) 80 (downcase ; canonical name
80 (downcase ;Canonical name 81 (mail-strip-quoted-names
81 (mail-strip-quoted-names 82 (or (rmail-get-header "To" msg)
82 (or (rmail-get-header "To" msg) 83 (rmail-get-header "Apparently-To" msg) ""))))))
83 (rmail-get-header "Apparently-To" msg) "")
84 ))))))
85 84
86;;;###autoload 85;;;###autoload
87(defun rmail-sort-by-correspondent (reverse) 86(defun rmail-sort-by-correspondent (reverse)
88 "Sort messages of current Rmail file by other correspondent. 87 "Sort messages of current Rmail buffer by other correspondent.
89If prefix argument REVERSE is non-nil, sort them in reverse order." 88This uses either the \"From\", \"Sender\", \"To\", or
89\"Apparently-To\" header, downcased. Uses the first header not
90excluded by `rmail-dont-reply-to-names'. If prefix argument
91REVERSE is non-nil, sorts in reverse order."
90 (interactive "P") 92 (interactive "P")
91 (rmail-sort-messages reverse 93 (rmail-sort-messages reverse
92 (function 94 (lambda (msg)
93 (lambda (msg) 95 (downcase
94 (rmail-select-correspondent 96 (rmail-select-correspondent
95 msg 97 msg
96 '("From" "Sender" "To" "Apparently-To")))))) 98 '("From" "Sender" "To" "Apparently-To"))))))
97 99
98(defun rmail-select-correspondent (msg fields) 100(defun rmail-select-correspondent (msg fields)
101 "Find the first header not excluded by `rmail-dont-reply-to-names'.
102MSG is a message number. FIELDS is a list of header names."
99 (let ((ans "")) 103 (let ((ans ""))
100 (while (and fields (string= ans "")) 104 (while (and fields (string= ans ""))
101 (setq ans 105 (setq ans
@@ -108,50 +112,65 @@ If prefix argument REVERSE is non-nil, sort them in reverse order."
108 112
109;;;###autoload 113;;;###autoload
110(defun rmail-sort-by-lines (reverse) 114(defun rmail-sort-by-lines (reverse)
111 "Sort messages of current Rmail file by number of lines. 115 "Sort messages of current Rmail buffer by the number of lines.
112If prefix argument REVERSE is non-nil, sort them in reverse order." 116If prefix argument REVERSE is non-nil, sorts in reverse order."
113 (interactive "P") 117 (interactive "P")
114 (rmail-sort-messages reverse 118 (rmail-sort-messages reverse
115 (function 119 (lambda (msg)
116 (lambda (msg) 120 (count-lines (rmail-msgbeg msg)
117 (count-lines (rmail-msgbeg msg) 121 (rmail-msgend msg)))))
118 (rmail-msgend msg))))))
119 122
120;;;###autoload 123;;;###autoload
121(defun rmail-sort-by-labels (reverse labels) 124(defun rmail-sort-by-labels (reverse labels)
122 "Sort messages of current Rmail file by labels. 125 "Sort messages of current Rmail buffer by labels.
123If prefix argument REVERSE is non-nil, sort them in reverse order. 126LABELS is a comma-separated list of labels. The order of these
124KEYWORDS is a comma-separated list of labels." 127labels specifies the order of messages: messages with the first
128label come first, messages with the second label come second, and
129so on. Messages that have none of these labels come last.
130If prefix argument REVERSE is non-nil, sorts in reverse order."
125 (interactive "P\nsSort by labels: ") 131 (interactive "P\nsSort by labels: ")
126 (or (string-match "[^ \t]" labels) 132 (or (string-match "[^ \t]" labels) ; need some non-whitespace
127 (error "No labels specified")) 133 (error "No labels specified"))
134 ;; Remove leading whitespace, add trailing comma.
128 (setq labels (concat (substring labels (match-beginning 0)) ",")) 135 (setq labels (concat (substring labels (match-beginning 0)) ","))
129 (let (labelvec) 136 (let (labelvec nmax)
137 ;; Convert "l1,..." into "\\(, \\|\\`\\)l1\\(,\\|\\'\\)" "..." ...
130 (while (string-match "[ \t]*,[ \t]*" labels) 138 (while (string-match "[ \t]*,[ \t]*" labels)
131 (setq labelvec (cons 139 (setq labelvec (cons
132 (concat ", ?\\(" 140 (concat "\\(, \\|\\`\\)"
133 (substring labels 0 (match-beginning 0)) 141 (substring labels 0 (match-beginning 0))
134 "\\),") 142 "\\(,\\|\\'\\)")
135 labelvec)) 143 labelvec))
136 (setq labels (substring labels (match-end 0)))) 144 (setq labels (substring labels (match-end 0))))
137 (setq labelvec (apply 'vector (nreverse labelvec))) 145 (setq labelvec (apply 'vector (nreverse labelvec))
146 nmax (length labelvec))
138 (rmail-sort-messages reverse 147 (rmail-sort-messages reverse
139 (function 148 ;; If no labels match, returns nmax; if they
140 (lambda (msg) 149 ;; match the first specified in LABELS,
141 (let ((n 0)) 150 ;; returns 0; if they match the second, returns 1; etc.
142 (while (and (< n (length labelvec)) 151 ;; Hence sorts as described in the doc-string.
143 (not (rmail-message-labels-p 152 (lambda (msg)
144 msg (aref labelvec n)))) 153 (let ((n 0)
145 (setq n (1+ n))) 154 (str (concat (rmail-get-attr-names msg)
146 n)))))) 155 ", "
156 (rmail-get-keywords msg))))
157 ;; No labels: can't match anything.
158 (if (string-equal ", " str)
159 nmax
160 (while (and (< n nmax)
161 (not (string-match (aref labelvec n)
162 str)))
163 (setq n (1+ n)))
164 n))))))
147 165
148;; Basic functions 166;; Basic functions
149(declare-function rmail-update-summary "rmailsum" (&rest ignore)) 167(declare-function rmail-update-summary "rmailsum" (&rest ignore))
150 168
151(defun rmail-sort-messages (reverse keyfun) 169(defun rmail-sort-messages (reverse keyfun)
152 "Sort messages of current Rmail file. 170 "Sort messages of current Rmail buffer.
153If 1st argument REVERSE is non-nil, sort them in reverse order. 171If REVERSE is non-nil, sorts in reverse order. Calls the
1542nd argument KEYFUN is called with a message number, and should return a key." 172function KEYFUN with a message number (it should return a sort key).
173Numeric keys are sorted numerically, all others as strings."
155 (with-current-buffer rmail-buffer 174 (with-current-buffer rmail-buffer
156 (let ((return-to-point 175 (let ((return-to-point
157 (if (rmail-buffers-swapped-p) 176 (if (rmail-buffers-swapped-p)
@@ -177,9 +196,8 @@ If 1st argument REVERSE is non-nil, sort them in reverse order.
177 ;; Decide predicate: < or string-lessp 196 ;; Decide predicate: < or string-lessp
178 (if (numberp (car (car sort-lists))) ;Is a key numeric? 197 (if (numberp (car (car sort-lists))) ;Is a key numeric?
179 'car-less-than-car 198 'car-less-than-car
180 (function 199 (lambda (a b)
181 (lambda (a b) 200 (string-lessp (car a) (car b))))))
182 (string-lessp (car a) (car b)))))))
183 (if reverse (setq sort-lists (nreverse sort-lists))) 201 (if reverse (setq sort-lists (nreverse sort-lists)))
184 ;; Now we enter critical region. So, keyboard quit is disabled. 202 ;; Now we enter critical region. So, keyboard quit is disabled.
185 (message "Reordering messages...") 203 (message "Reordering messages...")
@@ -187,7 +205,8 @@ If 1st argument REVERSE is non-nil, sort them in reverse order.
187 (inhibit-read-only t) 205 (inhibit-read-only t)
188 (current-message nil) 206 (current-message nil)
189 (msgnum 1) 207 (msgnum 1)
190 (msginfo nil)) 208 (msginfo nil)
209 (undo (not (eq buffer-undo-list t))))
191 ;; There's little hope that we can easily undo after that. 210 ;; There's little hope that we can easily undo after that.
192 (buffer-disable-undo (current-buffer)) 211 (buffer-disable-undo (current-buffer))
193 (goto-char (rmail-msgbeg 1)) 212 (goto-char (rmail-msgbeg 1))
@@ -201,7 +220,7 @@ If 1st argument REVERSE is non-nil, sort them in reverse order.
201 (insert-buffer-substring 220 (insert-buffer-substring
202 (current-buffer) (nth 2 msginfo) (nth 3 msginfo)) 221 (current-buffer) (nth 2 msginfo) (nth 3 msginfo))
203 ;; The last message may not have \n\n after it. 222 ;; The last message may not have \n\n after it.
204 (unless (bobp) 223 (unless (bolp)
205 (insert "\n")) 224 (insert "\n"))
206 (unless (looking-back "\n\n") 225 (unless (looking-back "\n\n")
207 (insert "\n")) 226 (insert "\n"))
@@ -215,6 +234,9 @@ If 1st argument REVERSE is non-nil, sort them in reverse order.
215 ;; Delete the dummy separator Z inserted before. 234 ;; Delete the dummy separator Z inserted before.
216 (delete-char 1) 235 (delete-char 1)
217 (setq quit-flag nil) 236 (setq quit-flag nil)
237 ;; If undo was on before, re-enable it. But note that it is
238 ;; disabled in mbox Rmail, so this is kind of pointless.
239 (if undo (buffer-enable-undo))
218 (rmail-set-message-counters) 240 (rmail-set-message-counters)
219 (rmail-show-message-1 current-message) 241 (rmail-show-message-1 current-message)
220 (if return-to-point 242 (if return-to-point
@@ -225,7 +247,7 @@ If 1st argument REVERSE is non-nil, sort them in reverse order.
225(autoload 'timezone-make-date-sortable "timezone") 247(autoload 'timezone-make-date-sortable "timezone")
226 248
227(defun rmail-make-date-sortable (date) 249(defun rmail-make-date-sortable (date)
228 "Make DATE sortable using the function string-lessp." 250 "Make DATE sortable using the function `string-lessp'."
229 ;; Assume the default time zone is GMT. 251 ;; Assume the default time zone is GMT.
230 (timezone-make-date-sortable date "GMT" "GMT")) 252 (timezone-make-date-sortable date "GMT" "GMT"))
231 253