-1st argument REVERSE is non-nil, sort them in reverse order.
-2nd argument KEYFUNC is called with message number, and should return a key."
- (let ((buffer-read-only nil)
- (sort-lists nil))
- (message "Finding sort keys...")
- (widen)
- (let ((msgnum 1))
- (while (>= rmail-total-messages msgnum)
- (setq sort-lists
- (cons (cons (funcall keyfunc msgnum) ;A sort key.
- (buffer-substring
- (rmail-msgbeg msgnum) (rmail-msgend msgnum)))
- sort-lists))
- (if (zerop (% msgnum 10))
- (message "Finding sort keys...%d" msgnum))
- (setq msgnum (1+ msgnum))))
- (or reverse (setq sort-lists (nreverse sort-lists)))
- (setq sort-lists
- (sort sort-lists
- (function
- (lambda (a b)
- (string-lessp (car a) (car b))))))
- (if reverse (setq sort-lists (nreverse sort-lists)))
- (message "Reordering buffer...")
- (delete-region (rmail-msgbeg 1) (rmail-msgend rmail-total-messages))
- (let ((msgnum 1))
- (while sort-lists
- (insert (cdr (car sort-lists)))
- (if (zerop (% msgnum 10))
- (message "Reordering buffer...%d" msgnum))
- (setq sort-lists (cdr sort-lists))
- (setq msgnum (1+ msgnum))))
- (rmail-set-message-counters)
- (rmail-show-message)))
+If 1st argument REVERSE is non-nil, sort them in reverse order.
+2nd argument KEYFUN is called with a message number, and should return a key."
+ (save-current-buffer
+ ;; If we are in a summary buffer, operate on the Rmail buffer.
+ (if (eq major-mode 'rmail-summary-mode)
+ (set-buffer rmail-buffer))
+ (let ((buffer-read-only nil)
+ (point-offset (- (point) (point-min)))
+ (predicate nil) ;< or string-lessp
+ (sort-lists nil))
+ (message "Finding sort keys...")
+ (widen)
+ (let ((msgnum 1))
+ (while (>= rmail-total-messages msgnum)
+ (setq sort-lists
+ (cons (list (funcall keyfun msgnum) ;Make sorting key
+ (eq rmail-current-message msgnum) ;True if current
+ (aref rmail-message-vector msgnum)
+ (aref rmail-message-vector (1+ msgnum)))
+ sort-lists))
+ (if (zerop (% msgnum 10))
+ (message "Finding sort keys...%d" msgnum))
+ (setq msgnum (1+ msgnum))))
+ (or reverse (setq sort-lists (nreverse sort-lists)))
+ ;; Decide predicate: < or string-lessp
+ (if (numberp (car (car sort-lists))) ;Is a key numeric?
+ (setq predicate (function <))
+ (setq predicate (function string-lessp)))
+ (setq sort-lists
+ (sort sort-lists
+ (function
+ (lambda (a b)
+ (funcall predicate (car a) (car b))))))
+ (if reverse (setq sort-lists (nreverse sort-lists)))
+ ;; Now we enter critical region. So, keyboard quit is disabled.
+ (message "Reordering messages...")
+ (let ((inhibit-quit t) ;Inhibit quit
+ (current-message nil)
+ (msgnum 1)
+ (msginfo nil))
+ ;; There's little hope that we can easily undo after that.
+ (buffer-disable-undo (current-buffer))
+ (goto-char (rmail-msgbeg 1))
+ ;; To force update of all markers.
+ (insert-before-markers ?Z)
+ (backward-char 1)
+ ;; Now reorder messages.
+ (while sort-lists
+ (setq msginfo (car sort-lists))
+ ;; Swap two messages.
+ (insert-buffer-substring
+ (current-buffer) (nth 2 msginfo) (nth 3 msginfo))
+ (delete-region (nth 2 msginfo) (nth 3 msginfo))
+ ;; Is current message?
+ (if (nth 1 msginfo)
+ (setq current-message msgnum))
+ (setq sort-lists (cdr sort-lists))
+ (if (zerop (% msgnum 10))
+ (message "Reordering messages...%d" msgnum))
+ (setq msgnum (1+ msgnum)))
+ ;; Delete the garbage inserted before.
+ (delete-char 1)
+ (setq quit-flag nil)
+ (buffer-enable-undo)
+ (rmail-set-message-counters)
+ (rmail-show-message current-message)
+ (goto-char (+ point-offset (point-min)))
+ (if (rmail-summary-exists)
+ (rmail-select-summary
+ (rmail-update-summary)))))))