From 7064c5393bd906e91776381a8becb7580dd91cd4 Mon Sep 17 00:00:00 2001 From: "Jacob S. Gordon" Date: Mon, 2 Jun 2025 21:06:37 -0400 Subject: [PATCH] world-clock: Add user option to control order of entries * 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 | 61 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/lisp/time.el b/lisp/time.el index 764ab705e11..c1c803f4a5a 100644 --- a/lisp/time.el +++ b/lisp/time.el @@ -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 -- 2.39.5