org-timer.el: Merge API for the two timers

* lisp/org-timer.el (org-timer-stop): Support countdown timers in addition
to relative timers.

* lisp/org-timer.el (org-timer-cancel-timer): Remove function.

* lisp/org-timer.el (org-timer-pause-or-continue): Support countdown
timers in addition to relative timers.

* testing/lisp/test-org-timer.el: New file.

* doc/org.texi: Merge relative and countdown timer nodes.

Several previous issues are fixed with these changes.

- org-timer-set-timer and org-timer-cancel-timer did not reset
  org-timer-start-time after countdown completed.

- Because org-timer-start did not return org-timer-pause-time to nil,
  the modeline remained stuck at the paused time.

- When org-timer-start was called with a countdown timer, the modeline
  was updated for the new relative timer, but the countdown timer
  remained scheduled.

- When org-timer-pause-or-continue was called with a countdown timer
  running, the modeline was put in a paused state, but the countdown
  timer remained scheduled.

- When org-timer-stop was called with a countdown timer running, the
  timer was removed from the modeline, but the countdown timer remained
  scheduled.

- When org-timer-set-timer was called with a paused relative timer, the
  relative timer was not reset properly (org-timer-pause-time was still
  non-nil) and the modeline remained in the paused state of the relative
  timer, even though the countdown timer was scheduled with
  run-with-timer.

- Running org-timer-set-timer at the beginning of an empty buffer
  resulted in an args-out-of-range error (due to the org-get-at-eol
  call).
This commit is contained in:
Kyle Meyer 2014-12-07 02:24:54 -05:00 committed by Nicolas Goaziou
parent dc460fcad1
commit 173b0cb6d6
4 changed files with 438 additions and 131 deletions

View File

@ -462,8 +462,7 @@ Dates and times
* Deadlines and scheduling:: Planning your work
* Clocking work time:: Tracking how long you spend on a task
* Effort estimates:: Planning work effort in advance
* Relative timer:: Notes with a running timer
* Countdown timer:: Starting a countdown timer for a task
* Timers:: Notes with a running timer
Creating timestamps
@ -5790,8 +5789,7 @@ is used in a much wider sense.
* Deadlines and scheduling:: Planning your work
* Clocking work time:: Tracking how long you spend on a task
* Effort estimates:: Planning work effort in advance
* Relative timer:: Notes with a running timer
* Countdown timer:: Starting a countdown timer for a task
* Timers:: Notes with a running timer
@end menu
@ -6793,60 +6791,56 @@ with the @kbd{/} key in the agenda (@pxref{Agenda commands}). If you have
these estimates defined consistently, two or three key presses will narrow
down the list to stuff that fits into an available time slot.
@node Relative timer
@section Taking notes with a relative timer
@node Timers
@section Taking notes with a timer
@cindex relative timer
@cindex countdown timer
@kindex ;
When taking notes during, for example, a meeting or a video viewing, it can
be useful to have access to times relative to a starting time. Org provides
such a relative timer and make it easy to create timed notes.
Org provides provides two types of timers. There is a relative timer that
counts up, which can be useful when taking notes during, for example, a
meeting or a video viewing. There is also a countdown timer.
The relative and countdown are started with separate commands.
@table @kbd
@orgcmd{C-c C-x 0,org-timer-start}
Start or reset the relative timer. By default, the timer is set to 0. When
called with a @kbd{C-u} prefix, prompt the user for a starting offset. If
there is a timer string at point, this is taken as the default, providing a
convenient way to restart taking notes after a break in the process. When
called with a double prefix argument @kbd{C-u C-u}, change all timer strings
in the active region by a certain amount. This can be used to fix timer
strings if the timer was not started at exactly the right moment.
@orgcmd{C-c C-x ;,org-timer-set-timer}
Start a countdown timer. The user is prompted for a duration.
@code{org-timer-default-timer} sets the default countdown value. Giving a
prefix numeric argument overrides this default value. This command is
available as @kbd{;} in agenda buffers.
@end table
Once started, relative and countdown timers are controlled with the same
commands.
@table @kbd
@orgcmd{C-c C-x .,org-timer}
Insert a relative time into the buffer. The first time you use this, the
timer will be started. When called with a prefix argument, the timer is
restarted.
Insert the value of the current relative or countdown timer into the buffer.
If no timer is running, the relative timer will be started. When called with
a prefix argument, the relative timer is restarted.
@orgcmd{C-c C-x -,org-timer-item}
Insert a description list item with the current relative time. With a prefix
argument, first reset the timer to 0.
Insert a description list item with the value of the current relative or
countdown timer. With a prefix argument, first reset the relative timer to
0.
@orgcmd{M-@key{RET},org-insert-heading}
Once the timer list is started, you can also use @kbd{M-@key{RET}} to insert
new timer items.
@c for key sequences with a comma, command name macros fail :(
@kindex C-c C-x ,
@item C-c C-x ,
Pause the timer, or continue it if it is already paused
(@command{org-timer-pause-or-continue}).
@c removed the sentence because it is redundant to the following item
@kindex C-u C-c C-x ,
@item C-u C-c C-x ,
@orgcmd{C-c C-x \,,org-timer-pause-or-continue}
Pause the timer, or continue it if it is already paused.
@orgcmd{C-c C-x _,org-timer-stop}
Stop the timer. After this, you can only start a new timer, not continue the
old one. This command also removes the timer from the mode line.
@orgcmd{C-c C-x 0,org-timer-start}
Reset the timer without inserting anything into the buffer. By default, the
timer is reset to 0. When called with a @kbd{C-u} prefix, reset the timer to
specific starting offset. The user is prompted for the offset, with a
default taken from a timer string at point, if any, So this can be used to
restart taking notes after a break in the process. When called with a double
prefix argument @kbd{C-u C-u}, change all timer strings in the active region
by a certain amount. This can be used to fix timer strings if the timer was
not started at exactly the right moment.
@end table
@node Countdown timer
@section Countdown timer
@cindex Countdown timer
@kindex C-c C-x ;
@kindex ;
Calling @code{org-timer-set-timer} from an Org mode buffer runs a countdown
timer. Use @kbd{;} from agenda buffers, @key{C-c C-x ;} everywhere else.
@code{org-timer-set-timer} prompts the user for a duration and displays a
countdown timer in the modeline. @code{org-timer-default-timer} sets the
default countdown value. Giving a prefix numeric argument overrides this
default value.
@node Capture - Refile - Archive
@chapter Capture - Refile - Archive
@cindex capture

View File

@ -72,6 +72,8 @@ This function inserted a Beamer specific template at point or in
current subtree. Use ~org-export-insert-default-template~ instead, as
it provides more features and covers all export back-ends. It is also
accessible from the export dispatcher.
*** Removed function ~org-timer-cancel-timer~
~org-timer-stop~ now stops both relative and countdown timers.
** Removed options
*** ~org-list-empty-line-terminates-plain-lists~ is deprecated
It will be kept in code base until next release, for backward
@ -174,6 +176,9 @@ special blocks and images. See docstring for more information.
Headlines, for which the property ~UNNUMBERED~ is non-nil, are now
exported without section numbers irrespective of their levels. The
property is inherited by children.
*** Countdown timers can now be paused.
~org-timer-pause-time~ wil now pause and restart both relative and
countdown timers.
** Miscellaneous
*** Strip all meta data from ITEM special property
ITEM special property does not contain TODO, priority or tags anymore.

View File

@ -1,4 +1,4 @@
;;; org-timer.el --- The relative timer code for Org-mode
;;; org-timer.el --- Timer code for Org mode
;; Copyright (C) 2008-2014 Free Software Foundation, Inc.
@ -24,13 +24,20 @@
;;
;;; Commentary:
;; This file contains the relative timer code for Org-mode
;; This file implements two types of timers for Org buffers:
;;
;; - A relative timer that counts up (from 0 or a specified offset)
;; - A countdown timer that counts down from a specified time
;;
;; The relative and countdown timers differ in their entry points.
;; Use `org-timer' or `org-timer-start' to start the relative timer,
;; and `org-timer-set-timer' to start the countdown timer.
;;; Code:
(require 'org)
(require 'org-clock)
(declare-function org-notify "org-clock" (notification &optional play-sound))
(declare-function org-agenda-error "org-agenda" ())
(defvar org-timer-start-time nil
@ -39,13 +46,22 @@
(defvar org-timer-pause-time nil
"Time when the timer was paused.")
(defvar org-timer-countdown-timer nil
"Current countdown timer.
This is a timer object if there is an active countdown timer,
'paused' if there is a paused countdown timer, and nil
otherwise.")
(defvar org-timer-countdown-timer-title nil
"Title for notification displayed when a countdown finishes.")
(defconst org-timer-re "\\([-+]?[0-9]+\\):\\([0-9]\\{2\\}\\):\\([0-9]\\{2\\}\\)"
"Regular expression used to match timer stamps.")
(defcustom org-timer-format "%s "
"The format to insert the time of the timer.
This format must contain one instance of \"%s\" which will be replaced by
the value of the relative timer."
the value of the timer."
:group 'org-time
:type 'string)
@ -76,13 +92,13 @@ nil current timer is not displayed"
"Hook run after relative timer is started.")
(defvar org-timer-stop-hook nil
"Hook run before relative timer is stopped.")
"Hook run before relative or countdown timer is stopped.")
(defvar org-timer-pause-hook nil
"Hook run before relative timer is paused.")
"Hook run before relative or countdown timer is paused.")
(defvar org-timer-continue-hook nil
"Hook run after relative timer is continued.")
"Hook run after relative or countdown timer is continued.")
(defvar org-timer-set-hook nil
"Hook run after countdown timer is set.")
@ -90,9 +106,6 @@ nil current timer is not displayed"
(defvar org-timer-done-hook nil
"Hook run after countdown timer reaches zero.")
(defvar org-timer-cancel-hook nil
"Hook run before countdown timer is canceled.")
;;;###autoload
(defun org-timer-start (&optional offset)
"Set the starting time for the relative timer to now.
@ -105,8 +118,12 @@ region will be shifted by a specific amount. You will be prompted for
the amount, with the default to make the first timer string in
the region 0:00:00."
(interactive "P")
(if (equal offset '(16))
(call-interactively 'org-timer-change-times-in-region)
(cond
((equal offset '(16))
(call-interactively 'org-timer-change-times-in-region))
(org-timer-countdown-timer
(user-error "Countdown timer is running. Cancel first"))
(t
(let (delta def s)
(if (not offset)
(setq org-timer-start-time (current-time))
@ -123,45 +140,66 @@ the region 0:00:00."
(setq delta (org-timer-hms-to-secs (org-timer-fix-incomplete s)))))
(setq org-timer-start-time
(seconds-to-time
(- (org-float-time) delta))))
;; Pass `current-time' result to `org-float-time'
;; (instead of calling without arguments) so that only
;; `current-time' has to be overriden in tests.
(- (org-float-time (current-time)) delta))))
(setq org-timer-pause-time nil)
(org-timer-set-mode-line 'on)
(message "Timer start time set to %s, current value is %s"
(format-time-string "%T" org-timer-start-time)
(org-timer-secs-to-hms (or delta 0)))
(run-hooks 'org-timer-start-hook))))
(run-hooks 'org-timer-start-hook)))))
(defun org-timer-pause-or-continue (&optional stop)
"Pause or continue the relative timer.
"Pause or continue the relative or countdown timer.
With prefix arg STOP, stop it entirely."
(interactive "P")
(cond
(stop (org-timer-stop))
((not org-timer-start-time) (error "No timer is running"))
(org-timer-pause-time
;; timer is paused, continue
(setq org-timer-start-time
(seconds-to-time
(-
(org-float-time)
(- (org-float-time org-timer-pause-time)
(org-float-time org-timer-start-time))))
org-timer-pause-time nil)
(org-timer-set-mode-line 'on)
(run-hooks 'org-timer-continue-hook)
(message "Timer continues at %s" (org-timer-value-string)))
(let ((start-secs (org-float-time org-timer-start-time))
(pause-secs (org-float-time org-timer-pause-time)))
(if org-timer-countdown-timer
(progn
(let ((new-secs (- start-secs pause-secs)))
(setq org-timer-countdown-timer
(org-timer--run-countdown-timer
new-secs org-timer-countdown-timer-title))
(setq org-timer-start-time
(time-add (current-time) (seconds-to-time new-secs)))))
(setq org-timer-start-time
;; Pass `current-time' result to `org-float-time'
;; (instead of calling without arguments) so that only
;; `current-time' has to be overriden in tests.
(seconds-to-time (- (org-float-time (current-time))
(- pause-secs start-secs)))))
(setq org-timer-pause-time nil)
(org-timer-set-mode-line 'on)
(run-hooks 'org-timer-continue-hook)
(message "Timer continues at %s" (org-timer-value-string))))
(t
;; pause timer
(when org-timer-countdown-timer
(cancel-timer org-timer-countdown-timer)
(setq org-timer-countdown-timer 'pause))
(run-hooks 'org-timer-pause-hook)
(setq org-timer-pause-time (current-time))
(org-timer-set-mode-line 'pause)
(message "Timer paused at %s" (org-timer-value-string)))))
(defun org-timer-stop ()
"Stop the relative timer."
"Stop the relative or countdown timer."
(interactive)
(unless org-timer-start-time
(user-error "No timer running"))
(when (timerp org-timer-countdown-timer)
(cancel-timer org-timer-countdown-timer))
(run-hooks 'org-timer-stop-hook)
(setq org-timer-start-time nil
org-timer-pause-time nil)
org-timer-pause-time nil
org-timer-countdown-timer nil)
(org-timer-set-mode-line 'off)
(message "Timer stopped"))
@ -191,11 +229,10 @@ it in the buffer."
(org-timer-secs-to-hms
(abs (floor (org-timer-seconds))))))
(defvar org-timer-timer-is-countdown nil)
(defun org-timer-seconds ()
(if org-timer-timer-is-countdown
(if org-timer-countdown-timer
(- (org-float-time org-timer-start-time)
(org-float-time (current-time)))
(org-float-time (or org-timer-pause-time (current-time))))
(- (org-float-time (or org-timer-pause-time (current-time)))
(org-float-time org-timer-start-time))))
@ -290,7 +327,7 @@ If the integer is negative, the string will start with \"-\"."
(defvar org-timer-mode-line-string nil)
(defun org-timer-set-mode-line (value)
"Set the mode-line display of the relative timer.
"Set the mode-line display for relative or countdown timer.
VALUE can be `on', `off', or `pause'."
(when (or (eq org-timer-display 'mode-line)
(eq org-timer-display 'both))
@ -349,35 +386,20 @@ VALUE can be `on', `off', or `pause'."
(concat " <" (substring (org-timer-value-string) 0 -1) ">"))
(force-mode-line-update)))
(defvar org-timer-current-timer nil)
(defun org-timer-cancel-timer ()
"Cancel the current timer."
(interactive)
(if (not org-timer-current-timer)
(message "No timer to cancel")
(run-hooks 'org-timer-cancel-hook)
(cancel-timer org-timer-current-timer)
(setq org-timer-current-timer nil
org-timer-timer-is-countdown nil)
(org-timer-set-mode-line 'off)
(message "Last timer canceled")))
(defun org-timer-show-remaining-time ()
"Display the remaining time before the timer ends."
(interactive)
(require 'time)
(if (not org-timer-current-timer)
(if (not org-timer-countdown-timer)
(message "No timer set")
(let* ((rtime (decode-time
(time-subtract (timer--time org-timer-current-timer)
(time-subtract (timer--time org-timer-countdown-timer)
(current-time))))
(rsecs (nth 0 rtime))
(rmins (nth 1 rtime)))
(message "%d minute(s) %d seconds left before next time out"
rmins rsecs))))
(defvar org-clock-sound)
;;;###autoload
(defun org-timer-set-timer (&optional opt)
"Prompt for a duration and set a timer.
@ -400,7 +422,10 @@ By default, the timer duration will be set to the number of
minutes in the Effort property, if any. You can ignore this by
using three `C-u' prefix arguments."
(interactive "P")
(let* ((effort-minutes (org-get-at-eol 'effort-minutes 1))
(when (and org-timer-start-time
(not org-timer-countdown-timer))
(user-error "Relative timer is running. Stop first"))
(let* ((effort-minutes (ignore-errors (org-get-at-eol 'effort-minutes 1)))
(minutes (or (and (not (equal opt '(64)))
effort-minutes
(number-to-string effort-minutes))
@ -415,47 +440,57 @@ using three `C-u' prefix arguments."
(org-timer-show-remaining-time)
(let* ((mins (string-to-number (match-string 0 minutes)))
(secs (* mins 60))
(hl (cond
((string-match "Org Agenda" (buffer-name))
(let* ((marker (or (get-text-property (point) 'org-marker)
(org-agenda-error)))
(hdmarker (or (get-text-property (point) 'org-hd-marker)
marker))
(pos (marker-position marker)))
(with-current-buffer (marker-buffer marker)
(widen)
(goto-char pos)
(org-show-entry)
(or (ignore-errors (org-get-heading))
(concat "File:" (file-name-nondirectory (buffer-file-name)))))))
((derived-mode-p 'org-mode)
(or (ignore-errors (org-get-heading))
(concat "File:" (file-name-nondirectory (buffer-file-name)))))
(t (error "Not in an Org buffer"))))
timer-set)
(if (or (and org-timer-current-timer
(or (equal opt '(16))
(y-or-n-p "Replace current timer? ")))
(not org-timer-current-timer))
(hl (org-timer--get-timer-title)))
(if (or (not org-timer-countdown-timer)
(equal opt '(16))
(y-or-n-p "Replace current timer? "))
(progn
(require 'org-clock)
(when org-timer-current-timer
(cancel-timer org-timer-current-timer))
(setq org-timer-current-timer
(run-with-timer
secs nil `(lambda ()
(setq org-timer-current-timer nil)
(org-notify ,(format "%s: time out" hl) ,org-clock-sound)
(setq org-timer-timer-is-countdown nil)
(org-timer-set-mode-line 'off)
(run-hooks 'org-timer-done-hook))))
(when (timerp org-timer-countdown-timer)
(cancel-timer org-timer-countdown-timer))
(setq org-timer-countdown-timer-title
(org-timer--get-timer-title))
(setq org-timer-countdown-timer
(org-timer--run-countdown-timer
secs org-timer-countdown-timer-title))
(run-hooks 'org-timer-set-hook)
(setq org-timer-timer-is-countdown t
org-timer-start-time
(time-add (current-time) (seconds-to-time (* mins 60))))
(setq org-timer-start-time
(time-add (current-time) (seconds-to-time secs)))
(setq org-timer-pause-time nil)
(org-timer-set-mode-line 'on))
(message "No timer set"))))))
(defun org-timer--run-countdown-timer (secs title)
"Start countdown timer that will last SECS.
TITLE will be appended to the notification message displayed when
time is up."
(let ((msg (format "%s: time out" title)))
(run-with-timer
secs nil `(lambda ()
(setq org-timer-countdown-timer nil
org-timer-start-time nil)
(org-notify ,msg ,org-clock-sound)
(org-timer-set-mode-line 'off)
(run-hooks 'org-timer-done-hook)))))
(defun org-timer--get-timer-title ()
"Construct timer title from heading or file name of Org buffer."
(cond
((derived-mode-p 'org-agenda-mode)
(let* ((marker (or (get-text-property (point) 'org-marker)
(org-agenda-error)))
(hdmarker (or (get-text-property (point) 'org-hd-marker)
marker)))
(with-current-buffer (marker-buffer marker)
(org-with-wide-buffer
(goto-char hdmarker)
(org-show-entry)
(or (ignore-errors (org-get-heading))
(buffer-name (buffer-base-buffer)))))))
((derived-mode-p 'org-mode)
(or (ignore-errors (org-get-heading))
(buffer-name (buffer-base-buffer))))
(t (error "Not in an Org buffer"))))
(provide 'org-timer)
;; Local variables:

View File

@ -0,0 +1,273 @@
;;; test-org-timer.el --- Tests for org-timer.el
;; Copyright (C) 2014 Kyle Meyer
;; Author: Kyle Meyer <kyle@kyleam.com>
;; 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 <http://www.gnu.org/licenses/>.
;;; Code:
(defmacro test-org-timer/with-temp-text (text &rest body)
"Like `org-test-with-temp-text', but set timer-specific variables.
Also, mute output from `message'."
(declare (indent 1))
`(cl-letf (((symbol-function 'message) (lambda (&rest args) nil)))
(org-test-with-temp-text ,text
(let (org-timer-start-time
org-timer-pause-time
org-timer-countdown-timer
org-timer-display)
(unwind-protect (progn ,@body)
(when (timerp org-timer-countdown-timer)
(cancel-timer org-timer-countdown-timer)))))))
(defmacro test-org-timer/with-current-time (time &rest body)
"Run BODY, setting `current-time' output to TIME."
(declare (indent 1))
`(cl-letf (((symbol-function 'current-time) (lambda () ,time)))
,@body))
;;; Time conversion and formatting
(ert-deftest test-org-timer/secs-to-hms ()
"Test conversion between HMS format and seconds."
;; Seconds to HMS, and back again
(should
(equal "0:00:30"
(org-timer-secs-to-hms 30)))
(should
(equal 30
(org-timer-hms-to-secs (org-timer-secs-to-hms 30))))
;; Minutes to HMS, and back again
(should
(equal "0:02:10"
(org-timer-secs-to-hms 130)))
(should
(equal 130
(org-timer-hms-to-secs (org-timer-secs-to-hms 130))))
;; Hours to HMS, and back again
(should
(equal "1:01:30"
(org-timer-secs-to-hms 3690)))
(should
(equal 3690
(org-timer-hms-to-secs (org-timer-secs-to-hms 3690))))
;; Negative seconds to HMS, and back again
(should
(equal "-1:01:30"
(org-timer-secs-to-hms -3690)))
(should
(equal -3690
(org-timer-hms-to-secs (org-timer-secs-to-hms -3690)))))
(ert-deftest test-org-timer/fix-incomplete ()
"Test conversion to complete HMS format."
;; No fix is needed.
(should
(equal "1:02:03"
(org-timer-fix-incomplete "1:02:03")))
;; Hour is missing.
(should
(equal "0:02:03"
(org-timer-fix-incomplete "02:03")))
;; Minute is missing.
(should
(equal "0:00:03"
(org-timer-fix-incomplete "03"))))
(ert-deftest test-org-timer/change-times ()
"Test changing HMS format by offset."
;; Add time.
(should
(equal "
1:31:15
4:00:55"
(org-test-with-temp-text "
0:00:25
2:30:05"
(org-timer-change-times-in-region (point-min) (point-max)
"1:30:50")
(buffer-string))))
;; Subtract time.
(should
(equal "
-1:30:25
0:59:15"
(org-test-with-temp-text "
0:00:25
2:30:05"
(org-timer-change-times-in-region (point-min) (point-max)
"-1:30:50")
(buffer-string)))))
;;; Timers
;; Dummy times for overriding `current-time'
(defvar test-org-timer/time0 '(21635 62793 797149 675000))
;; Add 3 minutes and 26 seconds.
(defvar test-org-timer/time1
(time-add test-org-timer/time0 (seconds-to-time 206)))
;; Add 2 minutes and 41 seconds (6 minutes and 7 seconds total).
(defvar test-org-timer/time2
(time-add test-org-timer/time1 (seconds-to-time 161)))
;; Add 4 minutes and 55 seconds (11 minutes and 2 seconds total).
(defvar test-org-timer/time3
(time-add test-org-timer/time2 (seconds-to-time 295)))
(ert-deftest test-org-timer/start-relative ()
"Test starting relative timer."
;; Insert plain timer string, starting with `org-timer-start'.
(should
(equal "0:03:26"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer))
(org-trim (buffer-string)))))
;; Insert item timer string.
(should
(equal "- 0:03:26 ::"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-item))
(org-trim (buffer-string)))))
;; Start with `org-timer'.
(should
(equal "0:00:00 0:03:26"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer))
(org-trim (buffer-string)))))
;; Restart with `org-timer'.
(should
(equal "0:00:00"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer '(4)))
(org-trim (buffer-string))))))
(ert-deftest test-org-timer/set-timer ()
"Test setting countdown timer."
(should
(equal "0:06:34"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-set-timer 10))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer))
(org-trim (buffer-string))))))
(ert-deftest test-org-timer/pause-timer ()
"Test pausing relative and countdown timers."
;; Pause relative timer.
(should
(equal "0:03:26"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-pause-or-continue))
(org-timer)
(org-trim (buffer-string)))))
;; Pause then continue relative timer.
(should
(equal "0:08:21"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-pause-or-continue))
(test-org-timer/with-current-time test-org-timer/time2
(org-timer-pause-or-continue))
(test-org-timer/with-current-time test-org-timer/time3
(org-timer))
(org-trim (buffer-string)))))
;; Pause then continue countdown timer.
(should
(equal "0:01:39"
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-set-timer 10))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-pause-or-continue))
(test-org-timer/with-current-time test-org-timer/time2
(org-timer-pause-or-continue))
(test-org-timer/with-current-time test-org-timer/time3
(org-timer))
(org-trim (buffer-string))))))
(ert-deftest test-org-timer/stop ()
"Test stopping relative and countdown timers."
;; Stop running relative timer.
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-stop))
(should-not org-timer-start-time))
;; Stop paused relative timer.
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-start))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-pause-or-continue)
(org-timer-stop))
(should-not org-timer-start-time)
(should-not org-timer-pause-time))
;; Stop running countdown timer.
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-set-timer 10))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-stop))
(should-not org-timer-start-time)
(should-not org-timer-countdown-timer))
;; Stop paused countdown timer.
(test-org-timer/with-temp-text ""
(test-org-timer/with-current-time test-org-timer/time0
(org-timer-set-timer 10))
(test-org-timer/with-current-time test-org-timer/time1
(org-timer-pause-or-continue)
(org-timer-stop))
(should-not org-timer-start-time)
(should-not org-timer-pause-time)
(should-not org-timer-countdown-timer)))
(ert-deftest test-org-timer/other-timer-error ()
"Test for error when other timer running."
;; Relative timer is running.
(should-error
(test-org-timer/with-temp-text ""
(org-timer-start)
(org-timer-set-timer 10)))
;; Countdown timer is running.
(should-error
(test-org-timer/with-temp-text ""
(org-timer-set-timer 10)
(org-timer-start))))
(provide 'test-org-timer)
;;; test-org-timer.el end here