branch: externals/tmr
commit cc3b8db6ddba05e6c722575611355248a2a95ead
Author: Steven Allen <ste...@stebalien.com>
Commit: Steven Allen <ste...@stebalien.com>

    Merge tmr-mode-line.el into tmr.el
---
 tmr-mode-line.el | 179 -------------------------------------------------------
 tmr.el           | 147 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 146 insertions(+), 180 deletions(-)

diff --git a/tmr-mode-line.el b/tmr-mode-line.el
deleted file mode 100644
index c55c553a5e..0000000000
--- a/tmr-mode-line.el
+++ /dev/null
@@ -1,179 +0,0 @@
-;;; tmr-mode-line.el --- Mode-line integration for tmr -*- lexical-binding: t 
-*-
-
-;; Copyright (C) 2025  Free Software Foundation, Inc.
-
-;;; Commentary:
-
-;; This package provides a mode-line component that displays active TMR May 
Ring
-;; timers with a countdown to when they fire.
-;;
-;; To use it, add the following to your init file:
-;;
-;; (require 'tmr-mode-line)
-;; (tmr-mode-line-mode 1)
-;;
-;; Customize the appearance with:
-;; - `tmr-mode-line-format': Format string for displaying each timer
-;; - `tmr-mode-line-separator': String used to separate multiple timers
-;; - `tmr-mode-line-max-timers': Maximum number of timers to display
-;; - `tmr-mode-line-max-desc-length': Max length for timer descriptions
-
-;;; Code:
-
-(require 'tmr)
-(require 'format-spec)
-(eval-when-compile (require 'subr-x))
-
-(defgroup tmr-mode-line nil
-  "Mode-line integration for TMR May Ring."
-  :link '(info-link :tag "Info Manual" "(tmr)")
-  :link '(url-link :tag "Homepage" "https://protesilaos.com/emacs/tmr";)
-  :link '(emacs-library-link :tag "Library Source" "tmr.el")
-  :group 'tmr)
-
-(defcustom tmr-mode-line-format "%r%d"
-  "Format string for displaying a timer in the mode-line.
-Available format specifiers:
-- %r: Remaining time.
-- %d: Timer description (truncated to `tmr-mode-line-max-desc-length')."
-  :type 'string
-  :group 'tmr-mode-line)
-
-(defcustom tmr-mode-line-separator " | "
-  "String used to separate multiple timers in the mode-line."
-  :type 'string
-  :group 'tmr-mode-line)
-
-(defcustom tmr-mode-line-max-timers 3
-  "Maximum number of timers to display in the mode-line.
-Set to nil to show all timers."
-  :type '(choice (const :tag "Show all" nil)
-                 (integer :tag "Maximum number"))
-  :group 'tmr-mode-line)
-
-(defcustom tmr-mode-line-max-desc-length 15
-  "Maximum length for timer descriptions in the mode-line.
-Longer descriptions will be truncated."
-  :type '(choice (const :tag "Don't truncate" nil)
-                 (integer :tag "Truncate"))
-  :group 'tmr-mode-line)
-
-(defcustom tmr-mode-line-prefix "⏰"
-  "Prefix string displayed before the timer list."
-  :type 'string
-  :group 'tmr-mode-line)
-
-(defface tmr-mode-line-active
-  '((t :inherit mode-line-emphasis))
-  "Face for active timers in the mode-line."
-  :group 'tmr-mode-line)
-
-(defface tmr-mode-line-soon
-  '((t :inherit warning))
-  "Face for timers that will expire in the next 2 minutes."
-  :group 'tmr-mode-line)
-
-(defface tmr-mode-line-urgent
-  '((t :inherit error))
-  "Face for timers that will expire in the next 30 seconds."
-  :group 'tmr-mode-line)
-
-(defvar tmr-mode-line-string nil
-  "TMR mode-line string.")
-(put 'tmr-mode-line-string 'risky-local-variable t)
-
-(defvar tmr-mode-line--update-timer nil
-  "Timer to update the mode-line.")
-
-(defun tmr-mode-line--format-remaining (timer)
-  "Format remaining time for TIMER with appropriate face."
-  (let* ((secs (float-time (time-subtract (tmr--timer-end-date timer) nil)))
-         (face (cond ((and (< secs 5) (evenp (truncate secs)))
-                      '((t :inherit tmr-mode-line-urgent :inverse-video t)))
-                     ((< secs 30) 'tmr-mode-line-urgent)
-                     ((= (truncate secs) 30)
-                      '((t :inherit tmr-mode-line-urgent :inverse-video t)))
-                     ((= (truncate secs) 60)
-                      '((t :inherit tmr-mode-line-soon :inverse-video t)))
-                     ((< secs 120) 'tmr-mode-line-soon)
-                     ((= (truncate secs) 120)
-                      '((t :inherit tmr-mode-line-soon :inverse-video t)))
-                     (t 'tmr-mode-line-active)))
-         (formatted (format-seconds
-                     (cond ((< secs 120) "%mm %ss%z")
-                           ((< secs (* 24 60 60)) "%hh %mm%z")
-                           (t "%dd %hh%z"))
-                     secs)))
-    (propertize formatted 'face face)))
-
-(defun tmr-mode-line--format-description (timer)
-  "Format description for TIMER, truncating if necessary."
-  (if-let* ((desc (tmr--timer-description timer)))
-    (concat " " (if tmr-mode-line-max-desc-length
-                    (truncate-string-to-width
-                     desc tmr-mode-line-max-desc-length
-                     nil nil t)
-                  desc))
-    ""))
-
-(defun tmr-mode-line--format-timer (timer)
-  "Format a single TIMER for display in the mode-line."
-  (propertize
-   (format-spec tmr-mode-line-format
-                `((?r . ,(tmr-mode-line--format-remaining timer))
-                  (?d . ,(tmr-mode-line--format-description timer))))
-   'help-echo (tmr--long-description timer)))
-
-(defun tmr-mode-line--get-active-timers ()
-  "Return a sorted list of active timers."
-  (thread-last tmr--timers
-               (seq-remove #'tmr--timer-finishedp)
-               (seq-sort-by #'tmr--timer-end-date #'time-less-p)))
-
-(defun tmr-mode-line--update ()
-  "Updates `tmr-mode-line-string' based on the current timer state."
-  (setq
-   tmr-mode-line-string
-   (if-let* ((active-timers (tmr-mode-line--get-active-timers)))
-       (let* ((truncate (and tmr-mode-line-max-timers
-                             (length> active-timers tmr-mode-line-max-timers)))
-              (timers-to-show (if truncate
-                                 (seq-take active-timers
-                                           tmr-mode-line-max-timers)
-                                active-timers)))
-         (concat
-          " " tmr-mode-line-prefix " "
-          (string-join (mapcar #'tmr-mode-line--format-timer timers-to-show)
-                       tmr-mode-line-separator)
-          (when truncate
-            (format " +%d" (- (length active-timers) 
tmr-mode-line-max-timers)))
-          " "))
-     "")))
-
-(defun tmr-mode-line-update ()
-  "Update the mode line with current timer information."
-  (tmr-mode-line--update)
-  (force-mode-line-update t))
-
-;;;###autoload
-(define-minor-mode tmr-mode-line-mode
-  "Display TMR May Ring timers in the global mode line."
-  :global t
-  :group 'tmr-mode-line
-  (if tmr-mode-line-mode
-      (progn
-        (unless global-mode-string (setq global-mode-string '("")))
-        (unless (memq 'tmr-mode-line-string global-mode-string)
-          (setq global-mode-string
-                (append global-mode-string '(tmr-mode-line-string))))
-        (setq tmr-mode-line--update-timer
-              (run-at-time t 1 #'tmr-mode-line-update))
-        (add-hook 'tmr--update-hook #'tmr-mode-line-update))
-    (when tmr-mode-line--update-timer
-      (cancel-timer tmr-mode-line--update-timer)
-      (setq tmr-mode-line--update-timer nil))
-    (setq tmr-mode-line-string nil)
-    (remove-hook 'tmr--update-hook #'tmr-mode-line-update)))
-
-(provide 'tmr-mode-line)
-;;; tmr-mode-line.el ends here
diff --git a/tmr.el b/tmr.el
index 5641dfafeb..0ef313ddd5 100644
--- a/tmr.el
+++ b/tmr.el
@@ -37,7 +37,10 @@
 ;;; Code:
 
 (require 'seq)
-(eval-when-compile (require 'cl-lib))
+(require 'format-spec)
+(eval-when-compile
+  (require 'cl-lib)
+  (require 'subr-x))
 
 (defgroup tmr ()
   "TMR May Ring: set timers using a simple notation."
@@ -143,6 +146,38 @@ meant for experienced users."
           :value-type ,display-buffer--action-custom-type)
   :package-version '(tmr . "1.1.0"))
 
+(defcustom tmr-mode-line-format "%r%d"
+  "Format string for displaying a timer in the mode-line.
+Available format specifiers:
+- %r: Remaining time.
+- %d: Timer description (truncated to `tmr-mode-line-max-desc-length')."
+  :type 'string
+  :group 'tmr)
+
+(defcustom tmr-mode-line-separator " | "
+  "String used to separate multiple timers in the mode-line."
+  :type 'string
+  :group 'tmr)
+
+(defcustom tmr-mode-line-max-timers 3
+  "Maximum number of timers to display in the mode-line.
+Set to nil to show all timers."
+  :type '(choice (const :tag "Show all" nil)
+                 (integer :tag "Maximum number"))
+  :group 'tmr)
+
+(defcustom tmr-mode-line-max-desc-length 15
+  "Maximum length for timer descriptions in the mode-line.
+Longer descriptions will be truncated."
+  :type '(choice (const :tag "Don't truncate" nil)
+                 (integer :tag "Truncate"))
+  :group 'tmr)
+
+(defcustom tmr-mode-line-prefix "⏰"
+  "Prefix string displayed before the timer list."
+  :type 'string
+  :group 'tmr)
+
 ;;;; Faces
 
 (defgroup tmr-faces ()
@@ -229,6 +264,21 @@ meant for experienced users."
   :package-version '(tmr . "1.1.0")
   :group 'tmr-faces)
 
+(defface tmr-mode-line-active
+  '((t :inherit mode-line-emphasis))
+  "Face for active timers in the mode-line."
+  :group 'tmr-faces)
+
+(defface tmr-mode-line-soon
+  '((t :inherit warning))
+  "Face for timers that will expire in the next 2 minutes."
+  :group 'tmr-faces)
+
+(defface tmr-mode-line-urgent
+  '((t :inherit error))
+  "Face for timers that will expire in the next 30 seconds."
+  :group 'tmr-faces)
+
 ;;;; Common helpers
 
 (cl-defstruct (tmr--timer
@@ -843,6 +893,101 @@ they are set to reasonable default values."
 (add-hook 'tmr--update-hook #'tmr-tabulated--refresh)
 (add-hook 'tmr--read-timer-hook #'tmr-tabulated--timer-at-point)
 
+;;;; Mode-line indicator
+
+(defvar tmr-mode-line-string nil
+  "TMR mode-line string.")
+(put 'tmr-mode-line-string 'risky-local-variable t)
+
+(defvar tmr-mode-line--update-timer nil
+  "Timer to update the mode-line.")
+
+(defun tmr-mode-line--format-remaining (timer)
+  "Format remaining time for TIMER with appropriate face."
+  (let* ((secs (float-time (time-subtract (tmr--timer-end-date timer) nil)))
+         (face (cond ((and (< secs 5) (evenp (truncate secs)))
+                      '((t :inherit tmr-mode-line-urgent :inverse-video t)))
+                     ((< secs 30) 'tmr-mode-line-urgent)
+                     ((= (truncate secs) 30)
+                      '((t :inherit tmr-mode-line-urgent :inverse-video t)))
+                     ((= (truncate secs) 60)
+                      '((t :inherit tmr-mode-line-soon :inverse-video t)))
+                     ((< secs 120) 'tmr-mode-line-soon)
+                     ((= (truncate secs) 120)
+                      '((t :inherit tmr-mode-line-soon :inverse-video t)))
+                     (t 'tmr-mode-line-active)))
+         (formatted (format-seconds
+                     (cond ((< secs 120) "%mm %ss%z")
+                           ((< secs (* 24 60 60)) "%hh %mm%z")
+                           (t "%dd %hh%z"))
+                     secs)))
+    (propertize formatted 'face face)))
+
+(defun tmr-mode-line--format-description (timer)
+  "Format description for TIMER, truncating if necessary."
+  (if-let* ((desc (tmr--timer-description timer)))
+    (concat " " (if tmr-mode-line-max-desc-length
+                    (truncate-string-to-width
+                     desc tmr-mode-line-max-desc-length
+                     nil nil t)
+                  desc))
+    ""))
+
+(defun tmr-mode-line--format-timer (timer)
+  "Format a single TIMER for display in the mode-line."
+  (propertize
+   (format-spec tmr-mode-line-format
+                `((?r . ,(tmr-mode-line--format-remaining timer))
+                  (?d . ,(tmr-mode-line--format-description timer))))
+   'help-echo (tmr--long-description timer)))
+
+(defun tmr-mode-line--get-active-timers ()
+  "Return a sorted list of active timers."
+  (thread-last tmr--timers
+               (seq-remove #'tmr--timer-finishedp)
+               (seq-sort-by #'tmr--timer-end-date #'time-less-p)))
+
+(defun tmr-mode-line--update ()
+  "Updates `tmr-mode-line-string' based on the current timer state."
+  (setq
+   tmr-mode-line-string
+   (if-let* ((active-timers (tmr-mode-line--get-active-timers)))
+       (let* ((truncate (and tmr-mode-line-max-timers
+                             (length> active-timers tmr-mode-line-max-timers)))
+              (timers-to-show (if truncate
+                                 (seq-take active-timers
+                                           tmr-mode-line-max-timers)
+                                active-timers)))
+         (concat
+          " " tmr-mode-line-prefix " "
+          (string-join (mapcar #'tmr-mode-line--format-timer timers-to-show)
+                       tmr-mode-line-separator)
+          (when truncate
+            (format " +%d" (- (length active-timers) 
tmr-mode-line-max-timers)))
+          " "))
+     ""))
+  (force-mode-line-update t))
+
+;;;###autoload
+(define-minor-mode tmr-mode-line-mode
+  "Display TMR May Ring timers in the global mode line."
+  :global t
+  :group 'tmr-mode-line
+  (if tmr-mode-line-mode
+      (progn
+        (unless global-mode-string (setq global-mode-string '("")))
+        (unless (memq 'tmr-mode-line-string global-mode-string)
+          (setq global-mode-string
+                (append global-mode-string '(tmr-mode-line-string))))
+        (setq tmr-mode-line--update-timer
+              (run-at-time t 1 #'tmr-mode-line--update))
+        (add-hook 'tmr--update-hook #'tmr-mode-line--update))
+    (when tmr-mode-line--update-timer
+      (cancel-timer tmr-mode-line--update-timer)
+      (setq tmr-mode-line--update-timer nil))
+    (setq tmr-mode-line-string nil)
+    (remove-hook 'tmr--update-hook #'tmr-mode-line--update)))
+
 ;;;; Ask if there are timers before exiting Emacs
 
 (defun tmr-kill-emacs-query-function ()

Reply via email to