emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 918669cb3d: Make list-times not include zero elements


From: Lars Ingebrigtsen
Subject: master 918669cb3d: Make list-times not include zero elements
Date: Wed, 13 Apr 2022 09:31:40 -0400 (EDT)

branch: master
commit 918669cb3db21eebc9fb409098a4395f131379ee
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Make list-times not include zero elements
    
    * doc/lispref/os.texi (Time Parsing): Mention %x.
    * lisp/calendar/time-date.el (format-seconds): Accept a new %x
    spec that removes trailing zeros (bug#54904).
    
    * lisp/emacs-lisp/timer-list.el (list-timers): Don't display
    trailing zero bits.
---
 doc/lispref/os.texi                   |  4 +++
 etc/NEWS                              |  5 ++++
 lisp/calendar/time-date.el            | 56 +++++++++++++++++++++++++----------
 lisp/emacs-lisp/timer-list.el         |  2 +-
 test/lisp/calendar/time-date-tests.el |  9 ++++--
 5 files changed, 57 insertions(+), 19 deletions(-)

diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 9cb9bc75d0..4ee893f860 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1961,6 +1961,10 @@ encountered.  For example, the default format used by
 @w{@code{"%Y, %D, %H, %M, %z%S"}} means that the number of seconds
 will always be produced, but years, days, hours, and minutes will only
 be shown if they are non-zero.
+@item %x
+Non-printing control flag that works along the same lines as
+@samp{%z}, but instead suppresses printing of trailing zero-value time
+elements.
 @item %%
 Produces a literal @samp{%}.
 @end table
diff --git a/etc/NEWS b/etc/NEWS
index 8665a825ce..c24f3f6ed5 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1856,6 +1856,11 @@ temporary transition aid for Emacs 27, has served its 
purpose.
 month, day, or time.  For example, (date-to-time "2021-12-04") now
 assumes a time of 00:00 instead of signaling an error.
 
++++
+** 'format-seconds' now allows suppressing zero-value trailing elements.
+The new "%x" non-printing control character will suppress zero-value
+elements that appear after "%x".
+
 +++
 ** New events for taking advantage of touchscreen devices.
 The events 'touchscreen-begin, 'touchscreen-update', and
diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el
index 51cf7eb213..0db973ea16 100644
--- a/lisp/calendar/time-date.el
+++ b/lisp/calendar/time-date.el
@@ -287,17 +287,23 @@ use.  \"%,1s\" means \"use one decimal\".
 
 The \"%z\" specifier does not print anything.  When it is used, specifiers
 must be given in order of decreasing size.  To the left of \"%z\", nothing
-is output until the first non-zero unit is encountered."
+is output until the first non-zero unit is encountered.
+
+The \"%x\" specifier does not print anything.  When it is used,
+specifiers must be given in order of decreasing size.  To the
+right of \"%x\", trailing zero units are not output."
   (let ((start 0)
         (units '(("y" "year"   31536000)
                  ("d" "day"       86400)
                  ("h" "hour"       3600)
                  ("m" "minute"       60)
                  ("s" "second"        1)
-                 ("z")))
+                 ("z")
+                 ("x")))
         (case-fold-search t)
-        spec match usedunits zeroflag larger prev name unit num zeropos
-        fraction)
+        spec match usedunits zeroflag larger prev name unit num
+        leading-zeropos trailing-zeropos fraction
+        chop-leading chop-trailing)
     (while (string-match "%\\.?[0-9]*\\(,[0-9]\\)?\\(.\\)" string start)
       (setq start (match-end 0)
             spec (match-string 2 string))
@@ -306,15 +312,16 @@ is output until the first non-zero unit is encountered."
             (error "Bad format specifier: `%s'" spec))
         (if (assoc (downcase spec) usedunits)
             (error "Multiple instances of specifier: `%s'" spec))
-        (if (string-equal (car match) "z")
+        (if (or (string-equal (car match) "z")
+                (string-equal (car match) "x"))
             (setq zeroflag t)
           (unless larger
             (setq unit (nth 2 match)
                   larger (and prev (> unit prev))
                   prev unit)))
         (push match usedunits)))
-    (and zeroflag larger
-         (error "Units are not in decreasing order of size"))
+    (when (and zeroflag larger)
+      (error "Units are not in decreasing order of size"))
     (unless (numberp seconds)
       (setq seconds (float-time seconds)))
     (setq fraction (mod seconds 1)
@@ -326,18 +333,25 @@ is output until the first non-zero unit is encountered."
       (when (string-match
              (format "%%\\(\\.?[0-9]+\\)?\\(,[0-9]+\\)?\\(%s\\)" spec)
              string)
-        (if (string-equal spec "z")     ; must be last in units
-            (setq string
-                  (replace-regexp-in-string
-                   "%z" ""
-                   (substring string (min (or zeropos (match-end 0))
-                                          (match-beginning 0)))))
+        (cond
+         ((string-equal spec "z")
+          (setq chop-leading (and leading-zeropos
+                                  (min leading-zeropos (match-beginning 0)))))
+         ((string-equal spec "x")
+          (setq chop-trailing t))
+         (t
           ;; Cf article-make-date-line in gnus-art.
           (setq num (floor seconds unit)
                 seconds (- seconds (* num unit)))
           ;; Start position of the first non-zero unit.
-          (or zeropos
-              (setq zeropos (unless (zerop num) (match-beginning 0))))
+          (when (and (not leading-zeropos)
+                     (not (zerop num)))
+            (setq leading-zeropos (match-beginning 0)))
+          (unless (zerop num)
+            (setq trailing-zeropos nil))
+          (when (and (not trailing-zeropos)
+                     (zerop num))
+            (setq trailing-zeropos (match-beginning 0)))
           (setq string
                 (replace-match
                  (format (if (match-string 2 string)
@@ -360,7 +374,17 @@ is output until the first non-zero unit is encountered."
                            (format " %s%s" name
                                    (if (= num 1) "" "s"))))
                  t t string))))))
-  (string-replace "%%" "%" string))
+    (let ((pre string))
+      (when (and chop-trailing trailing-zeropos)
+        (setq string (substring string 0 trailing-zeropos)))
+      (when chop-leading
+        (setq string (substring string chop-leading)))
+      ;; If we ended up removing everything, return the formatted
+      ;; string in full.
+      (when (equal string "")
+        (setq string pre)))
+    (setq string (replace-regexp-in-string "%[zx]" "" string)))
+  (string-trim (string-replace "%%" "%" string)))
 
 (defvar seconds-to-string
   (list (list 1 "ms" 0.001)
diff --git a/lisp/emacs-lisp/timer-list.el b/lisp/emacs-lisp/timer-list.el
index c93a50cabf..aef18d0ba2 100644
--- a/lisp/emacs-lisp/timer-list.el
+++ b/lisp/emacs-lisp/timer-list.el
@@ -62,7 +62,7 @@
                   ((numberp repeat)
                    (propertize
                     (format "%12s" (format-seconds
-                                    "%dd %hh %mm %z%,1ss" repeat))
+                                    "%x%dd %hh %mm %z%,1ss" repeat))
                     'help-echo "Repeat interval"))
                   ((null repeat)
                    (propertize "           -" 'help-echo "Runs once"))
diff --git a/test/lisp/calendar/time-date-tests.el 
b/test/lisp/calendar/time-date-tests.el
index 5a37c91493..fd4d5ac8a1 100644
--- a/test/lisp/calendar/time-date-tests.el
+++ b/test/lisp/calendar/time-date-tests.el
@@ -88,14 +88,19 @@
 (ert-deftest test-format-seconds ()
   (should (equal (format-seconds "%y %d %h %m %s %%" 0) "0 0 0 0 0 %"))
   (should (equal (format-seconds "%y %d %h %m %s %%" 9999999) "0 115 17 46 39 
%"))
-  (should (equal (format-seconds "%y %d %h %m %z %s %%" 1) " 1 %"))
+  (should (equal (format-seconds "%y %d %h %m %z %s %%" 1) "1 %"))
   (should (equal (format-seconds "%mm %ss" 66) "1m 6s"))
   (should (equal (format-seconds "%mm %5ss" 66) "1m     6s"))
   (should (equal (format-seconds "%mm %.5ss" 66.4) "1m 00006s"))
 
   (should (equal (format-seconds "%mm %,1ss" 66.4) "1m 6.4s"))
   (should (equal (format-seconds "%mm %5,1ss" 66.4) "1m   6.4s"))
-  (should (equal (format-seconds "%mm %.5,1ss" 66.4) "1m 006.4s")))
+  (should (equal (format-seconds "%mm %.5,1ss" 66.4) "1m 006.4s"))
+
+  (should (equal (format-seconds "%hh %z%x%mm %ss" (* 60 2)) "2m"))
+  (should (equal (format-seconds "%hh %z%mm %ss" (* 60 2)) "2m 0s"))
+  (should (equal (format-seconds "%hh %x%mm %ss" (* 60 2)) "0h 2m"))
+  (should (equal (format-seconds "%hh %x%mm %ss" 0) "0h 0m 0s")))
 
 (ert-deftest test-ordinal ()
   (should (equal (date-ordinal-to-time 2008 271)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]