forked from kawsark/pomo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pomo.sh
executable file
·316 lines (279 loc) · 9.28 KB
/
pomo.sh
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
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#!/bin/bash
# Copyright (c) 2013, James Spencer.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#--- pomo.sh ---
# pomo.sh is a simple Pomodoro timer. It works by creating a file ($POMO) and
# inspecting the modification timestamp of that file to determine for how long
# a Pomodoro block has been running. Pausing a Pomodoro block works by storing
# how long the Pomodoro block has been running in the $POMO file. A paused
# Pomodoro block can then be resumed by updating the modification timestamp of
# the POMO file accordingly.
#--- Check environment ---
if [ "$(uname)" == "Darwin" ] || [ "${POMO_PREFIX_CMDS}" == "true" ]; then
# Use GNU coreutils installed with a prefix
DATE_CMD="gdate"
STAT_CMD="gstat"
else
DATE_CMD="date"
STAT_CMD="stat"
fi
#--- Pomodoro functions ---
function pomo_start {
# Start new pomo block (work+break cycle).
test -e "$(dirname -- "$POMO")" || mkdir -p "$(dirname -- "$POMO")"
:> "$POMO" # remove saved time stamp due to a pause.
touch "$POMO"
}
function pomo_isstopped {
# Return 0 if stopped, 1 otherwise.
# pomo.sh is stopped if the POMO file does not exist.
[[ ! -e "$POMO" ]]
return $?
}
function pomo_stop {
# Stop pomo cycles.
rm -f "$POMO"
}
function pomo_stamp {
# Set the timestamp of the POMO file to $1 seconds ago.
ago=$1
mtime=$(${DATE_CMD} --date "@$(( $(date +%s) - ago))" +%m%d%H%M.%S)
:> "$POMO" # erase saved time stamp due to a pause.
touch -m -t "$mtime" "$POMO"
}
function pomo_ispaused {
# Return 0 if paused, 1 otherwise.
# pomo.sh is paused if the POMO file contains any information.
[[ $(wc -l < "$POMO") -gt 0 ]]
return $?
}
function pomo_pause {
# Toggle the pause status on the POMO file.
running=$(pomo_stat)
if pomo_isstopped || pomo_ispaused; then
# Restart a stopped/paused pomo block by updating the time stamp of the POMO
# file.
pomo_stamp "$running"
else
# Pause a pomo block.
echo "$running" > "$POMO"
fi
}
function pomo_update {
# Update the time stamp on POMO a new cycle has started.
running=$(pomo_stat)
block_time=$(( (WORK_TIME+BREAK_TIME)*60 ))
if [[ $running -ge $block_time ]]; then
ago=$(( running % block_time )) # We should've started the new cycle a while ago?
mtime=$(${DATE_CMD} --date "@$(( $(date +%s) - ago))" +%m%d%H%M.%S)
touch -m -t "$mtime" "$POMO"
fi
}
function pomo_stat {
# Return number of seconds since start of pomo block (work+break cycle).
[[ -e "$POMO" ]] && running=$(cat "$POMO") || running=0
if [[ -z $running ]]; then
pomo_start=$(${STAT_CMD} -c +%Y "$POMO")
now=$(${DATE_CMD} +%s)
running=$((now-pomo_start))
fi
echo $running
}
function pomo_clock {
# Print out how much time is remaining in block.
# WMM:SS indicates MM:SS left in the work block.
# BMM:SS indicates MM:SS left in the break block.
if ! pomo_isstopped; then
pomo_update
running=$(pomo_stat)
left=$(( WORK_TIME*60 - running ))
if [[ $left -lt 0 ]]; then
left=$(( left + BREAK_TIME*60 ))
prefix=B
else
prefix=W
fi
pomo_ispaused && prefix=P$prefix
min=$(( left / 60 ))
sec=$(( left - 60*min ))
printf "%2s%02d:%02d\n" $prefix $min $sec
else
printf " --:--\n"
fi
}
function pomo_status {
while true; do
pomo_clock
sleep 1
done
}
function pomo_msg {
# Send a message using the GUI or console at the end of the next
# work or break block. This requires a Pomodoro session to
# have already been started...
[[ -e "$POMO" ]] || return 1
pomo_update
running=$(pomo_stat)
while true; do
left=$(( WORK_TIME*60 - running ))
work=true
if [[ $left -lt 0 ]]; then
left=$(( left + BREAK_TIME*60 ))
work=false
fi
sleep $left
# pomo_stat is time from the start of the work+block cycle.
# 1. If switching from work->break then stat >= running + left.
# 2. If switching from break->work then either
# stat >= running + left (haven't updated timestamp) or
# stat < running (have just updated the timestamp from a
# separate pomo call, e.g. using pomo status).
stat=$(pomo_stat)
[[ $stat -ge $(( running + left )) ]] && break
$work || { [[ $stat -lt $running ]] && break; }
running=$stat
done
if [[ $(( stat - running - left )) -le 1 ]]; then
if $work; then
$MSG_CALLBACK 0 # end of work block
else
$MSG_CALLBACK 1 # end of break block
fi
fi
return 0
}
function pomo_notify {
while true; do
if pomo_msg; then
# sleep for a second so that the timestamp of POMO is not the
# current time (i.e. allow next unit to start).
sleep 1
else
sleep 60
fi
done
}
function pomo_msg_callback {
block_type=$1
if [[ $block_type -eq 0 ]]; then
msg='End of a work period. Time for a break!'
elif [[ $block_type -eq 1 ]]; then
msg='End of a break period. Time for work!'
else
echo "Unknown block type"
exit 1
fi
send_msg "$msg"
}
function send_msg {
if [ "$(uname)" == "Darwin" ]; then
osascript -e "tell app \"System Events\" to display dialog \"${1}\"" &> /dev/null
elif command -v notify-send &> /dev/null; then
notify-send -a "Pomodoro" "${1}"
else
echo "${1}"
fi
}
#--- Help ---
function pomo_usage {
# Print out usage message.
cat <<END
pomo.sh [-h] [-c file] [start | stop | pause | clock | status | notify | usage]
pomo.sh - a simple Pomodoro timer.
Options:
-c file
Specify the path to the config file containing variable definitions.
-h
Print this usage message.
Actions:
start
Start Pomodoro timer.
stop
Stop Pomodoro timer.
pause
Pause a running Pomodoro timer or restart a paused Pomodoro timer.
clock
Print how much time (minutes and seconds) is remaining in the current
Pomodoro cycle. A prefix of B indicates a break period, a prefix of
W indicates a work period and a prefix of P indicates the current period is
paused.
notify
Raise a notification at the end of every Pomodoro work and break block in
an infinite loop. Requires notify-send (linux) or osascript (OS X).
status
Continuously print the current status of the Pomodoro timer once a second,
in the same format as the clock action.
usage
Print this usage message.
Note that the notify and status actions (unlike all others) do not terminate and
are best run in the background.
Environment variables:
POMO_CONFIG
Location of the config file. Default: \$XDG_CONFIG_HOME/pomo.cfg. Can also
be set using the -c option.
POMO_FILE
Location of the Pomodoro file used to store the duration of the Pomodoro
period (mostly using timestamps). Multiple Pomodoro timers can be run by
using different files. Default: \$HOME/.local/share/pomo.
POMO_WORK_TIME
Duration of the work period in minutes. Default: 25.
POMO_BREAK_TIME
Duration of the break period in minutes. Default: 5.
POMO_MSG_CALLBACK
Function to call at the end of a period, with argument of 0 for end of a
work period and 1 for the end of a break period. Default: pomo_msg_callback.
Environment variables other than POMO_CONFIG can also be set in POMO_CONFIG,
which is sourced if it exists.
END
}
#--- Command-line interface ---
action=
config=${POMO_CONFIG:-"$XDG_CONFIG_HOME/pomo.cfg"}
while getopts "hc:" arg; do
case $arg in
c)
config=$OPTARG
;;
h|?)
action=usage
;;
esac
done
shift $((OPTIND-1))
actions="start stop pause clock usage notify status"
for act in $actions; do
if [[ $act == "$1" ]]; then
action=$act
break
fi
done
#--- Configuration (can be set via environment variables) ---
[[ -e ${config} ]] && source "${config}"
POMO=${POMO_FILE:-"$HOME/.local/share/pomo"}
WORK_TIME=${POMO_WORK_TIME:-25}
BREAK_TIME=${POMO_BREAK_TIME:-5}
MSG_CALLBACK=${POMO_MSG_CALLBACK:-pomo_msg_callback}
#--- Run! ---
if [[ -n $action ]]; then
pomo_"$action"
else
[[ $# -gt 0 ]] && echo "Unknown option/action: $1." || echo "Action not supplied."
pomo_usage
fi