forked from mirrors/org-mode
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:
parent
dc460fcad1
commit
173b0cb6d6
84
doc/org.texi
84
doc/org.texi
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
273
testing/lisp/test-org-timer.el
Normal file
273
testing/lisp/test-org-timer.el
Normal 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
|
Loading…
Reference in a new issue