-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtomato-timer.el
258 lines (199 loc) · 8.4 KB
/
tomato-timer.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
;;; tomato-timer.el --- A tomato-timer using pomodoro technique -*- lexical-binding: t; -*-
;; Copyright (C) 2022 qdzhang
;; Author: qdzhang <[email protected]>
;; Created: 21 October 2022
;; URL: https://github.com/qdzhang/tomato-timer
;; Version: 0.2
;; Keywords: timer, pomodoro technique
;; Package-Requires: ((emacs "26.1"))
;; SPDX-License-Identifier: GPL-3.0-or-later
;; This file is not part of GNU Emacs.
;;; License:
;; 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:
;; Tomato-timer
;; ============
;; A tomato-timer using pomodoro technique. Use the built-in
;; `notifications' library.
;; Installation
;; ~~~~~~~~~~~~
;; Download the repository, then
;; ,----
;; | (load "/path/to/tomato-timer.el")
;; | (require 'tomato-timer)
;; `----
;; Usage
;; ~~~~~
;; `M-x Tomato-timer' . This function will start a new tomato timer.
;; Use `list-timers' to show all timer. If you want to close a tomato
;; timer, put your point in the entry, press `c' will cancel it.
;; Customization
;; ~~~~~~~~~~~~~
;; - `tomato-timer-play-sound-p' : whether play sound when a tomato-timer
;; ends. Default is `t' , set to nil to make it silent.
;; - `tomato-timer-audio-file-path' : the path of alert audio
;; file. Default is the plugin directory.
;; - `tomato-timer-audio-player' : the audio player to play the alert
;; audio. Default is mpv.
;; - `tomato-timer-mpv-args' : the extra mpv arguments. Default is
;; `--no-config' in order to avoid conflict with your other fancy mpv
;; configurations.
;; - `tomato-timer-work-time' : the time in minutes for a tomato-timer
;; period. Default is `25'.
;; - `tomato-timer-show-modeline-indicator-p': whether show timer indicator
;; in modeline. Default is `t', set `nil' will not show indicator.
;; - `tomato-timer-notification-title' : the title of the
;; notification. Default is `Tomato ends' .
;; - `tomato-timer-notification-body' : the body of the
;; notification. Default is `<NUMBER> min passed, take a break!' .
;; - `tomato-timer-mode-line-indicator-delimiter' : the delimiter of the
;; mode line indicator. It is a list contains two string elements, first is
;; the left delimiter, and the second is the right delimiter. Default
;; is `'("" "")' .
;; Credit
;; ~~~~~~
;; The mode line indicator is modified from syohex's
;; [emacs-mode-line-timer]<https://github.com:/syohex/emacs-mode-line-timer>.
;;; Code:
(require 'notifications)
(defgroup tomato-timer nil
"tomato-timer"
:prefix "tomato-timer-"
:group 'convenience)
(defconst tomato-timer-dir
(file-name-directory (or load-file-name buffer-file-name))
"tomato-timer directory where audio files store")
(defcustom tomato-timer-play-sound-p t
"Should tomato-timer play sounds when the timer ends.
Set to nil will make alert silent."
:group 'tomato-timer
:type 'boolean)
(defcustom tomato-timer-audio-file-path
(convert-standard-filename
(expand-file-name "tone.ogg"
tomato-timer-dir))
"The alert audio file path"
:group 'tomato-timer
:type 'string)
(defcustom tomato-timer-audio-player "mpv"
"The audio player used to play the alert sound. Default is mpv."
:group 'tomato-timer
:type 'string)
(defcustom tomato-timer-mpv-args
"--no-config"
"The arguments used for mpv"
:group 'tomato-timer
:type 'string)
(defcustom tomato-timer-work-time 25
"Length of time in minutes for a tomato-timer period"
:group 'tomato-timer
:type 'integer)
(defcustom tomato-timer-show-modeline-indicator-p t
"Whether show timer indicator in modeline."
:group 'tomato-timer
:type 'boolean)
(defcustom tomato-timer-notification-title "Tomato ends"
"The title of notification sent by `tomato-send-notification'."
:group 'tomato-timer
:type 'string)
(defcustom tomato-timer-notification-body
(concat (number-to-string tomato-timer-work-time)
" min passed, take a break!")
"The body of notification sent by `tomato-send-notification'."
:group 'tomato-timer
:type 'string)
(defcustom tomato-timer-mode-line-indicator-delimiter '("" "")
"The delimiter of tomato-timer mode line indicator.
This value is a list contains two string, the first element of the list is the
left delimiter, and the second is the right delimiter."
:group 'tomato-timer
:type 'string)
(defface tomato-timer-modeline-indicator-face
'((t (:weight bold)))
"tomato-timer-modeline-face")
(defun tomato-timer-minutes-to-seconds (minutes)
"Convert the minutes time to seconds"
(* 60 minutes))
(defun tomato-play-alert-sound ()
"Play the sound when tomato clock ends"
(start-process "tomato-alert"
"*tomato-play-audio-buffer*"
tomato-timer-audio-player
tomato-timer-mpv-args
tomato-timer-audio-file-path))
(defun tomato-send-notification ()
"When the tomato clock ends, send a notification"
(notifications-notify :title tomato-timer-notification-title
:body tomato-timer-notification-body)
(when tomato-timer-play-sound-p
(tomato-play-alert-sound)))
(defvar tomato-timer--timer nil)
(defvar tomato-timer--remainder-seconds 0)
(defvar tomato-timer--mode-line "")
(defun tomato-timer--set-remainder-second (minutes)
(setq tomato-timer--remainder-seconds (tomato-timer-minutes-to-seconds minutes)))
(defun tomato-timer--time-to-string (seconds)
(format "%02d:%02d" (/ seconds 60) (mod seconds 60)))
(defun tomato-timer-mode-line-indicator-delimiter-left ()
(car tomato-timer-mode-line-indicator-delimiter))
(defun tomato-timer-mode-line-indicator-delimiter-right ()
(cadr tomato-timer-mode-line-indicator-delimiter))
(defun tomato-timer--propertize-mode-line ()
(unless (string-empty-p tomato-timer--mode-line)
(concat " "
(tomato-timer-mode-line-indicator-delimiter-left)
(propertize tomato-timer--mode-line 'face 'tomato-timer-modeline-indicator-face)
(tomato-timer-mode-line-indicator-delimiter-right))))
(defun tomato-timer--set-mode-line ()
(setq tomato-timer--mode-line
(tomato-timer--time-to-string tomato-timer--remainder-seconds)))
(defun tomato-timer--tick ()
"Decrease the remainder seconds."
(let ((remainder-seconds (1- tomato-timer--remainder-seconds)))
(if (< remainder-seconds 0)
(tomato-timer-stop)
(cl-decf tomato-timer--remainder-seconds)
(tomato-timer--set-mode-line)
(tomato-timer--propertize-mode-line)
(force-mode-line-update))))
(defun tomato-timer-stop ()
"Stop the current `tomato-timer--timer', and restore modeline.
This function should only be used to remove the timer indicator in modeline when
you want to cancel a tomato-timer. In other scenarios, once the timer
`tomato-send-notification' ends, this function is invoked automatically."
(interactive)
(cancel-timer tomato-timer--timer)
(setq tomato-timer--timer nil
tomato-timer--mode-line "")
(setq-default mode-line-format (cdr mode-line-format))
(force-mode-line-update))
(defun tomato-timer-show-mode-line-indicator ()
"Show current timer indicator in mode line"
(tomato-timer--set-remainder-second tomato-timer-work-time)
(setq tomato-timer--timer (run-with-timer 0 1 'tomato-timer--tick))
(unless (member '(:eval (tomato-timer--propertize-mode-line)) mode-line-format)
(setq-default mode-line-format
(cons '(:eval (tomato-timer--propertize-mode-line))
mode-line-format))))
;;;###autoload
(defun tomato-timer ()
"Set a tomato timer for 25 minutes."
(interactive)
(message "Set a tomato timer for %s minutes." tomato-timer-work-time)
(run-with-timer
(tomato-timer-minutes-to-seconds tomato-timer-work-time)
nil 'tomato-send-notification)
;; Show timer in modeline
(when tomato-timer-show-modeline-indicator-p
(tomato-timer-show-mode-line-indicator)))
(provide 'tomato-timer)
;;; tomato-timer.el ends here