[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/tmr 6602891c8f 02/10: Decompose tmr.el into several fil
From: |
ELPA Syncer |
Subject: |
[elpa] externals/tmr 6602891c8f 02/10: Decompose tmr.el into several files |
Date: |
Sun, 15 May 2022 02:58:17 -0400 (EDT) |
branch: externals/tmr
commit 6602891c8f18a9463a9be8ef14db3a09920be124
Author: Damien Cassou <damien@cassou.me>
Commit: Protesilaos Stavrou <info@protesilaos.com>
Decompose tmr.el into several files
This commit also adds 3 hooks:
- tmr-timer-created-functions
- tmr-timer-completed-functions
- tmr-timer-cancelled-functions
---
tmr-notification.el | 66 ++++++++++++++++++++++
tmr-sound.el | 64 ++++++++++++++++++++++
tmr.el | 155 +++++++++++++++++++---------------------------------
3 files changed, 186 insertions(+), 99 deletions(-)
diff --git a/tmr-notification.el b/tmr-notification.el
new file mode 100644
index 0000000000..d0647dfefd
--- /dev/null
+++ b/tmr-notification.el
@@ -0,0 +1,66 @@
+;;; tmr-notification.el --- Display timers in a notification list -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+;; Author: Protesilaos Stavrou <info@protesilaos.com>,
+;; Damien Cassou <damien@cassou.me>
+;; Maintainer: Protesilaos Stavrou <info@protesilaos.com>
+;; URL: https://git.sr.ht/~protesilaos/tmr
+;; Mailing list: https://lists.sr.ht/~protesilaos/tmr
+;; Version: 0.2.3
+;; Package-Requires: ((emacs "27.1"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Provides a function to display a desktop notification. This is
+;; useful to get a passive popup when a timer completes. Read
+;; (info \"(elisp) Desktop Notifications\") for details.
+
+;;; Code:
+(require 'tmr)
+(require 'tmr-sound)
+(require 'notifications)
+
+(defcustom tmr-notification-urgency 'normal
+ "The urgency level of the desktop notification.
+Values can be `low', `normal' (default), or `critical'.
+
+The desktop environment or notification daemon is responsible for
+such notifications."
+ :type '(choice
+ (const :tag "Low" low)
+ (const :tag "Normal" normal)
+ (const :tag "Critical" critical))
+ :group 'tmr)
+
+;;;###autoload
+(defun tmr-notification-notify (timer)
+ "Dispatch a notification for TIMER.
+
+Read: (info \"(elisp) Desktop Notifications\") for details."
+ (let ((title "TMR May Ring (Emacs tmr package)")
+ (body (tmr--long-description-for-completed-timer timer)))
+ (notifications-notify
+ :title title
+ :body body
+ :app-name "GNU Emacs"
+ :urgency tmr-notification-urgency
+ :sound-file tmr-sound-file)))
+
+(provide 'tmr-notification)
+;;; tmr-notification.el ends here
diff --git a/tmr-sound.el b/tmr-sound.el
new file mode 100644
index 0000000000..be279e02d1
--- /dev/null
+++ b/tmr-sound.el
@@ -0,0 +1,64 @@
+;;; tmr-sound.el --- Play a sound -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+;; Author: Protesilaos Stavrou <info@protesilaos.com>,
+;; Damien Cassou <damien@cassou.me>
+;; Maintainer: Protesilaos Stavrou <info@protesilaos.com>
+;; URL: https://git.sr.ht/~protesilaos/tmr
+;; Mailing list: https://lists.sr.ht/~protesilaos/tmr
+;; Version: 0.2.3
+;; Package-Requires: ((emacs "27.1"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Provides a function to play a configurable sound file. This is
+;; useful to get an audio notification when a timer completes. This
+;; feature requires "ffplay" (part of ffmpeg) to be in the path.
+
+;; Choose the sound file through the `tmr-sound-file' option: if its
+;; value is nil or if the file is not found, no sound will be played.
+
+;;; Code:
+(require 'tmr)
+
+(defcustom tmr-sound-file
+ "/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga"
+ "Path to sound file used by `tmr--play-sound'.
+If nil, don't play any sound."
+ :type '(choice
+ file
+ (const :tag "Off" nil))
+ :group 'tmr)
+
+;; NOTE 2022-04-21: Emacs has a `play-sound' function but it only
+;; supports .wav and .au formats. Also, it does not work on all
+;; platforms and Emacs needs to be compiled --with-sound capabilities.
+;;;###autoload
+(defun tmr-sound-play (&optional _timer)
+ "Play `tmr-sound-file' using the 'ffplay' executable (ffmpeg).
+TIMER is unused."
+ (when-let* ((sound tmr-sound-file))
+ (when (file-exists-p sound)
+ (unless (executable-find "ffplay")
+ (user-error "Cannot play %s without `ffplay'" sound))
+ (call-process-shell-command
+ (format "ffplay -nodisp -autoexit %s >/dev/null 2>&1" sound) nil 0))))
+
+(provide 'tmr-sound)
+;;; tmr-sound.el ends here
diff --git a/tmr.el b/tmr.el
index 47269d8d7b..7648f09095 100644
--- a/tmr.el
+++ b/tmr.el
@@ -111,32 +111,10 @@
;;; Code:
-(require 'notifications)
-
(defgroup tmr ()
"TMR May Ring: set timers using a simple notation."
:group 'data)
-(defcustom tmr-sound-file
- "/usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga"
- "Path to sound file used by `tmr--play-sound'.
-If nil, don't play any sound."
- :type '(choice file
- (const :tag "Off" nil))
- :group 'tmr)
-
-(defcustom tmr-notification-urgency 'normal
- "The urgency level of the desktop notification.
-Values can be `low', `normal' (default), or `critical'.
-
-The desktop environment or notification daemon is responsible for
-such notifications."
- :type '(choice
- (const :tag "Low" low)
- (const :tag "Normal" normal)
- (const :tag "Critical" critical))
- :group 'tmr)
-
(defcustom tmr-descriptions-list (list "Boil water" "Prepare tea" "Bake bread")
"Optional description candidates for the current `tmr'.
These are provided as completion candidates when `tmr' is called
@@ -145,11 +123,31 @@ used."
:type '(repeat string)
:group 'tmr)
-(defcustom tmr-notify-function #'tmr-notifications-notify
- "Function called to send notification.
-It should take two string arguments: the title and the message."
- :type 'function
- :group 'tmr)
+(defcustom tmr-timer-created-functions
+ (list #'tmr-print-message-for-created-timer)
+ "Functions to execute when a timer is created.
+Each function must accept a timer as argument."
+ :type 'hook
+ :options '(tmr-print-message-for-created-timer))
+
+(declare-function tmr-sound-play "ext:tmr-sound.el")
+(declare-function tmr-notification-notify "ext:tmr-notification.el")
+
+(defcustom tmr-timer-completed-functions
+ (list #'tmr-print-message-for-completed-timer
+ #'tmr-sound-play
+ #'tmr-notification-notify)
+ "Functions to execute when a timer is completed.
+Each function must accept a timer as argument."
+ :type 'hook
+ :options (list #'tmr-print-message-for-completed-timer
+ #'tmr-sound-play
+ #'tmr-notification-notify))
+
+(defcustom tmr-timer-cancelled-functions nil
+ "Functions to execute when a timer is created.
+Each function must accept a timer as argument."
+ :type 'hook)
(cl-defstruct (tmr-timer
(:constructor tmr--timer-create)
@@ -187,6 +185,20 @@ It should take two string arguments: the title and the
message."
(format " [%s]" (propertize description 'face 'bold))
""))))
+(defun tmr--long-description-for-completed-timer (timer)
+ "Return a human-readable description of completed TIMER.
+This includes the creation and completion dates as well as the
+optional `tmr--timer-description'."
+ (let ((start (tmr--format-creation-date timer))
+ (end (tmr--format-end-date timer))
+ (description (tmr--timer-description timer)))
+ (format "Time is up!\n%s%s %s\n%s %s"
+ (if description (format "%s\n" description) "")
+ (propertize "Started" 'face 'success)
+ start
+ (propertize "Ended" 'face 'success)
+ end)))
+
(defun tmr--format-creation-date (timer)
"Return a string representing when TIMER was created."
(tmr--format-time (tmr--timer-creation-date timer)))
@@ -221,56 +233,6 @@ It should take two string arguments: the title and the
message."
("w" (user-error "TMR Made Ridiculous; append character for [m]inutes,
[h]ours, [s]econds"))
(_ (* num 60)))))))
-;; NOTE 2022-04-21: Emacs has a `play-sound' function but it only
-;; supports .wav and .au formats. Also, it does not work on all
-;; platforms and Emacs needs to be compiled --with-sound capabilities.
-(defun tmr--play-sound ()
- "Play `tmr-sound-file' using the 'ffplay' executable (ffmpeg)."
- (when-let* ((sound tmr-sound-file))
- (when (file-exists-p sound)
- (unless (executable-find "ffplay")
- (user-error "Cannot play %s without `ffplay'" sound))
- (call-process-shell-command
- (format "ffplay -nodisp -autoexit %s >/dev/null 2>&1" sound) nil 0))))
-
-(defun tmr-notifications-notify (title message)
- "Dispatch notification titled TITLE with MESSAGE via D-Bus.
-
-Read: (info \"(elisp) Desktop Notifications\") for details."
- (notifications-notify
- :title title
- :body message
- :app-name "GNU Emacs"
- :urgency tmr-notification-urgency
- :sound-file tmr-sound-file))
-
-(defun tmr--notify-send-notification (title message)
- "Send notification with TITLE and MESSAGE using `tmr-notify-function'."
- (funcall tmr-notify-function title message))
-
-(defun tmr--notify (timer)
- "Send notification for TIMER."
- (let* ((description (tmr--timer-description timer))
- (desc-plain (if description
- (concat "\n" description)
- ""))
- (desc-propertized (if description
- (concat " [" (propertize description 'face
'bold) "]")
- ""))
- (start (tmr--format-creation-date timer))
- (end (tmr--format-end-date timer)))
- (setf (tmr--timer-donep timer) t)
- (tmr--notify-send-notification
- "TMR May Ring (Emacs tmr package)"
- (format "Time is up!\nStarted: %s\nEnded: %s%s" start end desc-plain))
- (message
- "TMR %s %s ; %s %s%s"
- (propertize "Start:" 'face 'success) start
- (propertize "End:" 'face 'error) end
- desc-propertized)
- (unless (plist-get (notifications-get-capabilities) :sound)
- (tmr--play-sound))))
-
(defvar tmr--timers nil
"List of timer objects.
Populated by `tmr' and then operated on by `tmr-cancel'.")
@@ -288,7 +250,8 @@ completion."
(if (not timer)
(user-error "No `tmr' to cancel")
(cancel-timer (tmr--timer-timer-object timer))
- (setq tmr--timers (cl-delete timer tmr--timers))))
+ (setq tmr--timers (cl-delete timer tmr--timers))
+ (run-hook-with-args 'tmr-timer-cancelled-functions timer)))
(defun tmr--read-timer ()
"Let the user choose a timer among all timers.
@@ -304,24 +267,13 @@ there are no timers, return nil."
(selection (completing-read "Timer: " timer-descriptions nil t)))
(cl-find selection timers :test #'string= :key
#'tmr--long-description))))))
-(defun tmr--echo-area (time &optional description)
- "Produce `message' for current `tmr' TIME.
-Optionally include DESCRIPTION."
- (let* ((specifier (substring time -1))
- (amount (substring time 0 -1))
- (start (tmr--format-time (current-time)))
- (unit (pcase specifier
- ("s" (format "%ss (s == second)" amount))
- ("h" (format "%sh (h == hour)" amount))
- (_ (concat time "m (m == minute)")))))
- (message "`tmr' started at %s for %s%s"
- ;; Remember: these are just faces. Don't get caught in the
- ;; semantics.
- (propertize start 'face 'success)
- (propertize unit 'face 'error)
- (if description
- (format " [%s]" (propertize description 'face 'bold))
- ""))))
+(defun tmr-print-message-for-created-timer (timer)
+ "Show a `message' informing the user that TIMER was created."
+ (message "%s" (tmr--long-description timer)))
+
+(defun tmr-print-message-for-completed-timer (timer)
+ "Show a `message' informing the user that TIMER has completed."
+ (message "%s" (tmr--long-description-for-completed-timer timer)))
(defvar tmr--duration-hist '()
"Minibuffer history of `tmr' durations.")
@@ -350,6 +302,11 @@ If DEFAULT is provided, use that as a default."
tmr-descriptions-list nil nil nil
'tmr--description-hist def)))
+(defun tmr--complete (timer)
+ "Mark TIMER as completed and execute `tmr-timer-completed-functions'."
+ (setf (tmr--timer-donep timer) t)
+ (run-hook-with-args 'tmr-timer-completed-functions timer))
+
;;;###autoload
(defun tmr (time &optional description)
"Set timer to TIME duration and notify after it elapses.
@@ -381,10 +338,10 @@ command `tmr-with-description' instead of this one."
:duration duration))
(timer-object (run-with-timer
duration nil
- #'tmr--notify timer)))
+ #'tmr--complete timer)))
(setf (tmr--timer-timer-object timer) timer-object)
- (tmr--echo-area time description)
- (push timer tmr--timers)))
+ (push timer tmr--timers)
+ (run-hook-with-args 'tmr-timer-created-functions timer)))
;;;###autoload
(defun tmr-with-description (time description)
- [elpa] externals/tmr updated (3d9242be83 -> 407da662a2), ELPA Syncer, 2022/05/15
- [elpa] externals/tmr b2b322a00f 03/10: tmr: placate the compiler about cl-lib and related, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr 6602891c8f 02/10: Decompose tmr.el into several files,
ELPA Syncer <=
- [elpa] externals/tmr 32f6f93aba 04/10: tmr-notification: remove needless quotes, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr 0ceb744885 01/10: tmr: Improve tmr--long-description, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr f5dcca3588 07/10: tmr: use only active timers for tmr-cancel, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr 3f8674546b 09/10: tmr: accept optional default in description prompt, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr 407da662a2 10/10: tmr: make tmr-clone prompt optionally, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr c7e0f6f118 06/10: tmr: tweak message for completed tmr, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr b2903077f5 08/10: tmr: store the original input of a timer, ELPA Syncer, 2022/05/15
- [elpa] externals/tmr c1e7580eec 05/10: tmr: print message for cancelled timer, ELPA Syncer, 2022/05/15