branch: externals/tmr
commit a637c1c17e789d422a3886a4e17c19c6b268a40b
Author: Protesilaos Stavrou <[email protected]>
Commit: Protesilaos Stavrou <[email protected]>
Implement pause functionality
---
README.org | 20 +++++++++---
tmr.el | 107 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 100 insertions(+), 27 deletions(-)
diff --git a/README.org b/README.org
index d486742356..e10b04febb 100644
--- a/README.org
+++ b/README.org
@@ -113,6 +113,13 @@ minibuffer prompt (=ack= by default) can be configured via
the user
option ~tmr-acknoledge-timer-text~ [ The confirmation text is
configurable as part of {{{development-version}}}. ]
+#+findex: tmr-toggle-pause
+The command ~tmr-toggle-pause~ pauses the given timer. The tabulated
+view has a column to show when a timer is paused
([[#h:51fe78e0-d614-492b-b7a3-fb6d5bd52a9a][Grid or tabulated view]]).
+Similarly, the mode line indicator adapts the text of the timer to
+tell that it is paused ([[#h:a1938fd5-64ef-4f4f-ade1-c7058d4062fc][Display
timers on the mode line]]). [ The
+~tmr-toggle-pause~ and related functionality is part of
{{{development-version}}}. ]
+
#+vindex: tmr-descriptions-list
The user option ~tmr-descriptions-list~ defines the completion
candidates that are shown at the description prompt. Its value can be
@@ -187,12 +194,14 @@ Timers can be viewed in a grid with ~tmr-tabulated-view~
(alias
~tmr-list-timers~). The data is placed in the =*tmr-tabulated-view*=
buffer and looks like this:
+[ The pause functionality is part of {{{development-version}}}. ]
+
#+begin_example
-Start End Duration Remaining Acknowledge? Description
+Start End Duration Remaining Paused? Acknowledge? Description
-10:26:05 10:36:05 10m 9m 45s Prepare tea
-10:25:50 10:30:50 5m 4m 31s Yes Test the feature
-10:25:04 10:35:04 10m 8m 44s
+08:49:41 09:19:46 30m 29m 17s Yes Work on
TMR for 30 minutes
+08:49:31 08:54:31 5m 3m 53s Prepare tea
+08:49:21 08:59:21 10m 8m 42s Yes Edit the
description with this one instead
#+end_example
If a timer has elapsed, it has a check mark associated with it,
@@ -250,6 +259,9 @@ Faces used in the tabulated view:
#+vindex: tmr-tabulated-remaining-time
- ~tmr-tabulated-remaining-time~ :: The timer's remaining time.
+#+vindex: tmr-tabulated-paused
+- ~tmr-tabulated-paused~ :: Whether the timer is paused or not.
+
#+vindex: tmr-tabulated-acknowledgement
- ~tmr-tabulated-acknowledgement~ :: Whether the timer needs to be
acknowledged.
diff --git a/tmr.el b/tmr.el
index c97575ae0e..d88c2d2883 100644
--- a/tmr.el
+++ b/tmr.el
@@ -120,6 +120,20 @@ Each function must accept a timer as argument."
Each function must accept a timer as argument."
:type 'hook)
+(defcustom tmr-timer-paused-functions
+ (list #'tmr-print-message-for-paused-timer)
+ "Functions to execute when a timer is paused.
+Each function must accept a timer as argument."
+ :package-version '(tmr . "1.3.0")
+ :type 'hook)
+
+(defcustom tmr-timer-resumed-functions
+ (list #'tmr-print-message-for-resumed-timer)
+ "Functions to execute when a timer is resumed.
+Each function must accept a timer as argument."
+ :package-version '(tmr . "1.3.0")
+ :type 'hook)
+
(defcustom tmr-finished-indicator "✔"
"Indicator for a finished timer, shown in `tmr-tabulated-view'."
:package-version '(tmr . "1.0.0")
@@ -249,6 +263,11 @@ Longer descriptions will be truncated."
:package-version '(tmr . "1.0.0")
:group 'tmr-faces)
+(defface tmr-paused '((t :inherit bold))
+ "Face for styling the description of a paused timer."
+ :package-version '(tmr . "1.3.0")
+ :group 'tmr-faces)
+
(defface tmr-tabulated-start-time
'((((class color) (min-colors 88) (background light))
:foreground "#004476")
@@ -279,6 +298,11 @@ Longer descriptions will be truncated."
:package-version '(tmr . "1.1.0")
:group 'tmr-faces)
+(defface tmr-tabulated-paused '((t :inherit bold))
+ "Face for styling the description of a paused timer."
+ :package-version '(tmr . "1.3.0")
+ :group 'tmr-faces)
+
(defface tmr-tabulated-acknowledgement
'((t :inherit bold))
"Acknowledgement indicator in the `tmr-tabulated-view'."
@@ -320,7 +344,6 @@ Longer descriptions will be truncated."
:documentation "Time at which the timer was created.")
(end-date
nil
- :read-only t
:documentation "Time at which the timer finishes.")
(finishedp
nil
@@ -341,7 +364,11 @@ Longer descriptions will be truncated."
(description
nil
:read-only nil
- :documentation "Optional string describing the purpose of the timer, e.g.,
\"Stop the oven\"."))
+ :documentation "Optional string describing the purpose of the timer, e.g.,
\"Stop the oven\".")
+ (paused-remaining
+ nil
+ :read-only nil
+ :documentation "Remaining seconds when the timer was paused or nil if not
paused."))
(defun tmr--long-description (timer)
"Return a human-readable description for TIMER."
@@ -368,6 +395,8 @@ Longer descriptions will be truncated."
(concat "; " (propertize "acknowledge" 'face
'tmr-must-be-acknowledged)))
((tmr--timer-finishedp timer)
(concat "; " (propertize "finished" 'face 'tmr-finished)))
+ ((when-let* ((remaining (tmr--timer-paused-remaining timer)))
+ (format "; %s: remaining %s" (propertize "PAUSED" 'face
'tmr-paused) (tmr--format-seconds remaining))))
(t ""))
(if description
(concat "; " (propertize description 'face 'tmr-description))
@@ -507,6 +536,24 @@ cancelling the original one."
(setf (tmr--timer-description timer) description)
(run-hooks 'tmr--update-hook))
+(defun tmr-toggle-pause (timer)
+ "Toggle pause/resume state of TIMER."
+ (interactive (list (tmr--read-timer "Pause/resume timer: " :active)))
+ (if-let* ((remaining (tmr--timer-paused-remaining timer)))
+ (progn
+ (setf (tmr--timer-end-date timer) (time-add (current-time) remaining))
+ (setf (tmr--timer-timer-object timer) (run-with-timer remaining nil
#'tmr--complete timer))
+ (setf (tmr--timer-paused-remaining timer) nil)
+ (run-hooks 'tmr--update-hook)
+ (run-hook-with-args 'tmr-timer-resumed-functions timer))
+ (let ((remaining (tmr--get-seconds timer)))
+ (when (> remaining 0)
+ (cancel-timer (tmr--timer-timer-object timer))
+ (setf (tmr--timer-paused-remaining timer) remaining)
+ (run-hooks 'tmr--update-hook)
+ (run-hook-with-args 'tmr-timer-paused-functions timer)))))
+
+
(defun tmr-toggle-acknowledge (timer)
"Toggle ackowledge flag of TIMER."
(interactive
@@ -628,6 +675,14 @@ Read Info node `(elisp) Desktop Notifications' for
details."
"Show a `message' informing the user that TIMER is cancelled."
(message "Cancelled: <<%s>>" (tmr--long-description timer)))
+(defun tmr-print-message-for-paused-timer (timer)
+ "Show a `message' informing the user that TIMER is paused."
+ (message "Paused: <<%s>> (REMAINING %s)" (tmr--long-description timer)
(tmr--format-remaining timer)))
+
+(defun tmr-print-message-for-resumed-timer (timer)
+ "Show a `message' informing the user that TIMER is resumed."
+ (message "Resumed: <<%s>> (REMAINING %s)" (tmr--long-description timer)
(tmr--format-remaining timer)))
+
(defvar tmr-duration-history nil
"Minibuffer history of `tmr' durations.")
@@ -808,8 +863,8 @@ This map should be bound to a global prefix key."
"t" #'tmr
"T" #'tmr-with-details
"l" #'tmr-tabulated-view
- "c" #'tmr-clone
"s" #'tmr-reschedule
+ "p" #'tmr-toggle-pause
"a" #'tmr-toggle-acknowledge
"e" #'tmr-edit-description
"r" #'tmr-remove
@@ -831,7 +886,8 @@ This map should be bound to a global prefix key."
"c" #'tmr-clone
"a" #'tmr-toggle-acknowledge
"e" #'tmr-edit-description
- "s" #'tmr-reschedule)
+ "s" #'tmr-reschedule
+ "p" #'tmr-toggle-pause)
;;;;; Integration with the `embark' package
@@ -843,7 +899,8 @@ This map should be bound to a global prefix key."
"c" #'tmr-clone
"a" #'tmr-toggle-acknowledge
"e" #'tmr-edit-description
- "s" #'tmr-reschedule)
+ "s" #'tmr-reschedule
+ "p" #'tmr-toggle-pause)
(defvar embark-keymap-alist)
(defvar embark-post-action-hooks)
@@ -887,6 +944,7 @@ they are set to reasonable default values."
(propertize (tmr--format-end-date timer) 'face 'tmr-tabulated-end-time)
(propertize (tmr--format-duration timer) 'face 'tmr-duration)
(propertize (tmr--format-remaining timer) 'face
'tmr-tabulated-remaining-time)
+ (propertize (if (tmr--timer-paused-remaining timer) "Yes" "") 'face
'tmr-paused)
(propertize (if (tmr--timer-acknowledgep timer) "Yes" "") 'face
'tmr-tabulated-acknowledgement)
(propertize (or (tmr--timer-description timer) "") 'face
'tmr-tabulated-description))))
@@ -938,6 +996,7 @@ they are set to reasonable default values."
("End" 10 t)
("Duration" 10 t)
("Remaining" 10 tmr-tabulated--compare-remaining)
+ ("Paused?" 8 t)
("Acknowledge?" 14 t)
("Description" 0 t)])
(add-hook 'window-configuration-change-hook #'tmr-tabulated--window-hook nil
t)
@@ -975,24 +1034,26 @@ they are set to reasonable default values."
(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) (= (% (truncate secs) 2) 0))
- '(tmr-mode-line-urgent (:inverse-video t)))
- ((< secs 30) 'tmr-mode-line-urgent)
- ((= (truncate secs) 30)
- '(tmr-mode-line-urgent (:inverse-video t)))
- ((= (truncate secs) 60)
- '(tmr-mode-line-soon (:inverse-video t)))
- ((< secs 120) 'tmr-mode-line-soon)
- ((= (truncate secs) 120)
- '(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)))
+ (if-let* ((remaining (tmr--timer-paused-remaining timer)))
+ (propertize (format "PAUSED %s" (tmr--format-seconds remaining)) 'face
'tmr-paused)
+ (let* ((secs (float-time (time-subtract (tmr--timer-end-date timer) nil)))
+ (face (cond ((and (< secs 5) (= (% (truncate secs) 2) 0))
+ '(tmr-mode-line-urgent (:inverse-video t)))
+ ((< secs 30) 'tmr-mode-line-urgent)
+ ((= (truncate secs) 30)
+ '(tmr-mode-line-urgent (:inverse-video t)))
+ ((= (truncate secs) 60)
+ '(tmr-mode-line-soon (:inverse-video t)))
+ ((< secs 120) 'tmr-mode-line-soon)
+ ((= (truncate secs) 120)
+ '(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."