]> git.eshelyaron.com Git - emacs.git/commitdiff
world-clock: Add user option to control order of entries
authorJacob S. Gordon <jacob.as.gordon@gmail.com>
Tue, 3 Jun 2025 01:06:37 +0000 (21:06 -0400)
committerEshel Yaron <me@eshelyaron.com>
Wed, 18 Jun 2025 08:13:33 +0000 (10:13 +0200)
* lisp/time.el (world-clock-sort-order): Add user option.
(world-clock--sort-entries): Add auxiliary sorting function.
(world-clock-display): Sort entries based on the new user option.
(Bug#78678)

(cherry picked from commit 9c6c7c4bb7c02d08a14fc6f5e2517f51a28e927c)

lisp/time.el

index 764ab705e1170d75e7d30b16f87bd1a3305c4e0c..c1c803f4a5a04b2861f007f44d19ce67c08773d2 100644 (file)
@@ -536,6 +536,36 @@ If the value is t instead of an alist, use the value of
   :type 'natnum
   :version "28.1")
 
+(defcustom world-clock-sort-order nil
+  "Sort order of entries in the `world-clock'.
+This variable can take a few different forms:
+
+- A nil value indicates no sorting, and the displayed order is the same
+  as in `world-clock-list'.  This is the default.
+
+- A string is taken as a format for `format-time-string', whose output
+  is used as the sorting key.  For example, an ISO 8601 format `\"%FT%T\"'
+  means entries are sorted in chronological order.
+
+- A cons cell of the form (STRING . BOOL) again provides a format for
+  `format-time-string'.  The boolean part controls the sort direction.
+  For example, `(\"%FT%T\" .  t)' means entries are sorted in reverse
+  chronological order.
+
+- A function that takes a list of (TIMEZONE LABEL) entries and a TIME as
+  arguments, and returns another list of entries."
+  :version "31.1"
+  :type '(choice (const :tag "No sorting" nil)
+                (const :tag "Chronological order" "%FT%T")
+                (const :tag "Reverse chronological order" ("%FT%T" . t))
+                (const :tag "Time of day order" "%T")
+                (const :tag "Reverse time of day order" ("%T" . t))
+                (string :tag "Format string")
+                (cons :tag "Format string and reverse flag"
+                      (string :tag "Format string")
+                      (boolean :tag "Reverse"))
+                (function :tag "Sorting function")))
+
 (defface world-clock-label
   '((t :inherit font-lock-variable-name-face))
   "Face for time zone label in `world-clock' buffer.")
@@ -562,15 +592,32 @@ See `world-clock'."
 (defvar world-clock--timer nil
   "The current world clock timer.")
 
+(defun world-clock--sort-entries (tzlist time)
+  "Sort TZLIST according to `world-clock-sort-order' at a given TIME."
+  (pcase world-clock-sort-order
+    ((pred null) tzlist)
+    ((or (and (pred stringp) format)
+        `(,(and (pred stringp) format) .
+          ,(and (pred booleanp) reverse)))
+     (sort tzlist
+          :key (lambda (entry)
+                 (format-time-string format time (car entry)))
+          :reverse reverse))
+    ((pred functionp) (funcall world-clock-sort-order tzlist time))
+    (_ (error "Invalid `world-clock-sort-order': `%s'"
+             world-clock-sort-order))))
+
 (defun world-clock-display (alist)
-  "Replace current buffer text with times in various zones, based on ALIST."
-  (let ((inhibit-read-only t)
-       (buffer-undo-list t)
-       (now (current-time))
-       (max-width 0)
-       result fmt)
+  "Replace current buffer text with times in various zones, based on ALIST.
+The entries are ordered according to `world-clock-sort-order'."
+  (let* ((inhibit-read-only t)
+        (buffer-undo-list t)
+        (now (current-time))
+        (zones (world-clock--sort-entries alist now))
+        (max-width 0)
+        result fmt)
     (erase-buffer)
-    (dolist (zone alist)
+    (dolist (zone zones)
       (let* ((label (cadr zone))
             (width (string-width label)))
        (push (cons label