mirror of
https://git.savannah.gnu.org/git/emacs/org-mode.git
synced 2024-11-23 07:18:53 +00:00
Added feature for resolving clocks due to idleness
See the new manual section on "Resolving idle time". (org-clock-resolve-clock): If keeping or subtracting time results in a clock out at a time in the past, and if the resolution occurred due to idleness or invoking `M-x org-resolve-clocks', remember that past moment in time. On the next clock in, the user will be prompted to see if they want to back-date their new clock to then. (org-clock-resolve): Do not jump the user to the location of a dangling clock if the resolution is occuring due to an idle timeout. In that case there is typically only one dangling clock, the active one, and there is no value gained by shuffling their windows around to show it to them. Being prompted to resolve an idle clock should be as inobtrusive as possible. (org-resolve-clocks-if-idle): New function that resolves only the currently active clock if the user has exceeded the time returned by `org-user-idle-seconds', based on the value of `org-clock-idle-time'. (org-clock-in): If, after resolving clocks, (org-clock-out): Cancel the `org-clock-idle-timer' on clock out.
This commit is contained in:
parent
57a7a4c15b
commit
abfc6babca
@ -3,6 +3,11 @@
|
||||
* org.texi (Pushing to MobileOrg): Mention that `org-directory'
|
||||
should be set.
|
||||
|
||||
2009-10-17 John Wiegley <johnw@newartisans.com>
|
||||
|
||||
* org.texi (Resolving idle time): Added a section on how idle and
|
||||
dangling clocks are resolved.
|
||||
|
||||
2009-10-14 Carsten Dominik <carsten.dominik@gmail.com>
|
||||
|
||||
* org.texi (Agenda commands): Document that SPC is a filter for
|
||||
|
71
doc/org.texi
71
doc/org.texi
@ -231,6 +231,7 @@ Dates and Times
|
||||
* Creating timestamps:: Commands which insert timestamps
|
||||
* Deadlines and scheduling:: Planning your work
|
||||
* Clocking work time:: Tracking how long you spend on a task
|
||||
* Resolving idle time::
|
||||
* Effort estimates:: Planning work effort in advance
|
||||
* Relative timer:: Notes with a running timer
|
||||
|
||||
@ -4703,6 +4704,7 @@ is used in a much wider sense.
|
||||
* Creating timestamps:: Commands which insert timestamps
|
||||
* Deadlines and scheduling:: Planning your work
|
||||
* Clocking work time:: Tracking how long you spend on a task
|
||||
* Resolving idle time::
|
||||
* Effort estimates:: Planning work effort in advance
|
||||
* Relative timer:: Notes with a running timer
|
||||
@end menu
|
||||
@ -5220,7 +5222,7 @@ subtree, with dates shifted in each copy. The command @kbd{C-c C-x c} was
|
||||
created for this purpose, it is described in @ref{Structure editing}.
|
||||
|
||||
|
||||
@node Clocking work time, Effort estimates, Deadlines and scheduling, Dates and Times
|
||||
@node Clocking work time, Resolving idle time, Deadlines and scheduling, Dates and Times
|
||||
@section Clocking work time
|
||||
|
||||
Org mode allows you to clock the time you spend on specific tasks in a
|
||||
@ -5405,7 +5407,72 @@ The @kbd{l} key may be used in the timeline (@pxref{Timeline}) and in
|
||||
the agenda (@pxref{Weekly/daily agenda}) to show which tasks have been
|
||||
worked on or closed during a day.
|
||||
|
||||
@node Effort estimates, Relative timer, Clocking work time, Dates and Times
|
||||
@node Resolving idle time, Effort estimates, Clocking work time, Dates and Times
|
||||
@section Resolving idle time
|
||||
@cindex resolve idle time
|
||||
|
||||
@cindex idle, resolve, dangling
|
||||
If you clock in on a work item, and then walk away from your
|
||||
computer---perhaps to take a phone call---you often need to ``resolve'' the
|
||||
time you were away by either subtracting it from the current clock, or
|
||||
applying it to another one.
|
||||
|
||||
@vindex org-clock-idle-time
|
||||
By customizing the variable @code{org-clock-idle-time} to some integer, such
|
||||
as 10 or 15, Emacs can alert you when you get back to your computer after
|
||||
being idle for that many minutes@footnote{On computers using Mac OS X,
|
||||
idleness is based on actual user idleness, not just Emacs' idle time.}, and
|
||||
ask what you want to do with the idle time. There will be a question waiting
|
||||
for you when you get back, indicating how much idle time has passed
|
||||
(constantly updated with the current amount), as well as a set of choices to
|
||||
correct the discrepancy:
|
||||
|
||||
@table @kbd
|
||||
@item k
|
||||
To keep some or all of the minutes and stay clocked in, press @key{k}. Org
|
||||
will ask how many of the minutes to keep. Press @key{RET} to keep them all,
|
||||
effectively changing nothing, or enter a number to keep that many minutes.
|
||||
@item K
|
||||
If you use the shift key and press @key{K}, it will keep however many minutes
|
||||
you request and then immediately clock out of that task. If you keep all of
|
||||
the minutes, this is the same as just clocking out of the current task.
|
||||
@item s
|
||||
To keep none of the minutes, use @key{s} to subtract all the away time from
|
||||
the clock, and then check back in from the moment you returned.
|
||||
@item S
|
||||
To keep none of the minutes and just clock out at the start of the away time,
|
||||
use the shift key and press @key{S}. Remember that using shift will always
|
||||
leave you clocked out, no matter which option you choose.
|
||||
@item C
|
||||
To cancel the clock altogether, use @key{C}. Note that if instead of
|
||||
cancelling you subtract the away time, and the resulting clock amount is less
|
||||
than a minute, the clock will still be cancelled rather than clutter up the
|
||||
log with an empty entry.
|
||||
@end table
|
||||
|
||||
What if you subtracted those away minutes from the current clock, and now
|
||||
want to apply them to a new clock? Simply clock in to any task immediately
|
||||
after the subtraction. Org will notice that you have subtracted time ``on
|
||||
the books'', so to speak, and will ask if you want to apply those minutes to
|
||||
the next task you clock in on.
|
||||
|
||||
There is one other instance when this clock resolution magic occurs. Say you
|
||||
were clocked in and hacking away, and suddenly your cat chased a mouse who
|
||||
scared a hamster that crashed into your UPS's power button! You suddenly
|
||||
lose all your buffers, but thanks to auto-save you still have your recent Org
|
||||
mode changes, including your last clock in.
|
||||
|
||||
If you restart Emacs and clock into any task, Org will notice that you have a
|
||||
dangling clock which was never clocked out from your last session. Using
|
||||
that clock's starting time as the beginning of the unaccounted-for period,
|
||||
Org will ask how you want to resolve that time. The logic and behavior is
|
||||
identical to dealing with away time due to idleness, it's just happening due
|
||||
to a recovery event rather than a set amount of idle time.
|
||||
|
||||
You can also check all the files visited by your Org agenda for dangling
|
||||
clocks at any time using @kbd{M-x org-resolve-clocks}.
|
||||
|
||||
@node Effort estimates, Relative timer, Resolving idle time, Dates and Times
|
||||
@section Effort estimates
|
||||
@cindex effort estimates
|
||||
|
||||
|
@ -31,6 +31,25 @@
|
||||
|
||||
2009-10-17 John Wiegley <johnw@newartisans.com>
|
||||
|
||||
* org-clock.el (org-clock-resolve-clock): If keeping or
|
||||
subtracting time results in a clock out at a time in the past, and
|
||||
if the resolution occurred due to idleness or invoking `M-x
|
||||
org-resolve-clocks', remember that past moment in time. On the
|
||||
next clock in, the user will be prompted to see if they want to
|
||||
back-date their new clock to then.
|
||||
(org-clock-resolve): Do not jump the user to the location of a
|
||||
dangling clock if the resolution is occuring due to an idle
|
||||
timeout. In that case there is typically only one dangling clock,
|
||||
the active one, and there is no value gained by shuffling their
|
||||
windows around to show it to them. Being prompted to resolve an
|
||||
idle clock should be as inobtrusive as possible.
|
||||
(org-resolve-clocks-if-idle): New function that resolves only the
|
||||
currently active clock if the user has exceeded the time returned
|
||||
by `org-user-idle-seconds', based on the value of
|
||||
`org-clock-idle-time'.
|
||||
(org-clock-in): If, after resolving clocks,
|
||||
(org-clock-out): Cancel the `org-clock-idle-timer' on clock out.
|
||||
|
||||
* org-clock.el (org-clock-resolve-clock): New function that
|
||||
resolves a clock to a specific time, closing or resuming as need
|
||||
be, and possibly even starting a new clock.
|
||||
|
@ -235,10 +235,14 @@ to add an effort property.")
|
||||
(put 'org-mode-line-string 'risky-local-variable t)
|
||||
|
||||
(defvar org-clock-mode-line-timer nil)
|
||||
(defvar org-clock-idle-timer nil)
|
||||
(defvar org-clock-heading "")
|
||||
(defvar org-clock-heading-for-remember "")
|
||||
(defvar org-clock-start-time "")
|
||||
|
||||
(defvar org-clock-left-over-time nil
|
||||
"If non-nil, user cancelled a clock; this is when leftover time started.")
|
||||
|
||||
(defvar org-clock-effort ""
|
||||
"Effort estimate of the currently clocking task")
|
||||
|
||||
@ -576,6 +580,8 @@ If necessary, clock-out of the currently active clock."
|
||||
(setcar clock temp)))
|
||||
|
||||
(defvar org-clock-clocking-in nil)
|
||||
(defvar org-clock-resolving-clocks nil)
|
||||
(defvar org-clock-resolving-clocks-due-to-idleness nil)
|
||||
|
||||
(defun org-clock-resolve-clock (clock resolve-to &optional close-p
|
||||
restart-p fail-quietly)
|
||||
@ -610,30 +616,32 @@ This routine can do one of many things:
|
||||
start a new clock for the same item
|
||||
else just enter a closing time for this clock
|
||||
and then start a new clock for the same item"
|
||||
(cond
|
||||
((null resolve-to)
|
||||
(org-clock-clock-cancel clock)
|
||||
(if (and restart-p (not org-clock-clocking-in))
|
||||
(org-clock-clock-in clock)))
|
||||
(let ((org-clock-resolving-clocks t))
|
||||
(cond
|
||||
((null resolve-to)
|
||||
(org-clock-clock-cancel clock)
|
||||
(if (and restart-p (not org-clock-clocking-in))
|
||||
(org-clock-clock-in clock)))
|
||||
|
||||
((eq resolve-to 'now)
|
||||
(if restart-p
|
||||
(error "RESTART-P is not valid here"))
|
||||
(if (or close-p org-clock-clocking-in)
|
||||
(org-clock-clock-out clock fail-quietly)
|
||||
(unless (org-is-active-clock clock)
|
||||
(org-clock-clock-in clock t))))
|
||||
((eq resolve-to 'now)
|
||||
(if restart-p
|
||||
(error "RESTART-P is not valid here"))
|
||||
(if (or close-p org-clock-clocking-in)
|
||||
(org-clock-clock-out clock fail-quietly)
|
||||
(unless (org-is-active-clock clock)
|
||||
(org-clock-clock-in clock t))))
|
||||
|
||||
((not (time-less-p resolve-to (current-time)))
|
||||
(error "RESOLVE-TO must refer to a time in the past"))
|
||||
((not (time-less-p resolve-to (current-time)))
|
||||
(error "RESOLVE-TO must refer to a time in the past"))
|
||||
|
||||
(t
|
||||
(if restart-p
|
||||
(error "RESTART-P is not valid here"))
|
||||
(org-clock-clock-out clock fail-quietly resolve-to)
|
||||
(unless org-clock-clocking-in
|
||||
(if (not close-p)
|
||||
(org-clock-clock-in clock))))))
|
||||
(t
|
||||
(if restart-p
|
||||
(error "RESTART-P is not valid here"))
|
||||
(org-clock-clock-out clock fail-quietly resolve-to)
|
||||
(unless org-clock-clocking-in
|
||||
(if close-p
|
||||
(setq org-clock-left-over-time last-valid)
|
||||
(org-clock-clock-in clock)))))))
|
||||
|
||||
(defun org-clock-resolve (clock &optional prompt-fn last-valid fail-quietly)
|
||||
"Resolve an open org-mode clock.
|
||||
@ -658,22 +666,23 @@ was started."
|
||||
(let* ((ch
|
||||
(save-window-excursion
|
||||
(save-excursion
|
||||
(org-with-clock clock
|
||||
(org-clock-goto))
|
||||
(with-current-buffer (marker-buffer (car clock))
|
||||
(goto-char (car clock))
|
||||
(if org-clock-into-drawer
|
||||
(ignore-errors
|
||||
(outline-flag-region (save-excursion
|
||||
(outline-back-to-heading t)
|
||||
(search-forward ":LOGBOOK:")
|
||||
(goto-char (match-beginning 0)))
|
||||
(save-excursion
|
||||
(outline-back-to-heading t)
|
||||
(search-forward ":LOGBOOK:")
|
||||
(search-forward ":END:")
|
||||
(goto-char (match-end 0)))
|
||||
nil))))
|
||||
(unless org-clock-resolving-clocks-due-to-idleness
|
||||
(org-with-clock clock
|
||||
(org-clock-goto))
|
||||
(with-current-buffer (marker-buffer (car clock))
|
||||
(goto-char (car clock))
|
||||
(if org-clock-into-drawer
|
||||
(ignore-errors
|
||||
(outline-flag-region (save-excursion
|
||||
(outline-back-to-heading t)
|
||||
(search-forward ":LOGBOOK:")
|
||||
(goto-char (match-beginning 0)))
|
||||
(save-excursion
|
||||
(outline-back-to-heading t)
|
||||
(search-forward ":LOGBOOK:")
|
||||
(search-forward ":END:")
|
||||
(goto-char (match-end 0)))
|
||||
nil)))))
|
||||
(let (char-pressed)
|
||||
(while (null char-pressed)
|
||||
(setq char-pressed
|
||||
@ -711,8 +720,6 @@ was started."
|
||||
(not (memq ch '(?K ?S ?C))))
|
||||
fail-quietly))))
|
||||
|
||||
(defvar org-clock-resolving-clocks nil)
|
||||
|
||||
(defun org-resolve-clocks (&optional also-non-dangling-p prompt-fn last-valid)
|
||||
"Resolve all currently open org-mode clocks.
|
||||
If `also-non-dangling-p' is non-nil, also ask to resolve
|
||||
@ -763,6 +770,26 @@ This routine returns a floating point number."
|
||||
emacs-idle))
|
||||
(org-emacs-idle-seconds)))
|
||||
|
||||
(defun org-resolve-clocks-if-idle ()
|
||||
"Resolve all currently open org-mode clocks.
|
||||
This is performed after `org-clock-idle-time' minutes, to check
|
||||
if the user really wants to stay clocked in after being idle for
|
||||
so long."
|
||||
(when (and org-clock-idle-time (not org-clock-resolving-clocks)
|
||||
org-clock-marker)
|
||||
(let ((idle (org-user-idle-seconds))
|
||||
(org-clock-resolving-clocks-due-to-idleness t))
|
||||
(if (> idle (* 60 org-clock-idle-time))
|
||||
(org-clock-resolve
|
||||
(cons org-clock-marker
|
||||
org-clock-start-time)
|
||||
(function
|
||||
(lambda (clock)
|
||||
(format "Clocked in & idle for %d mins"
|
||||
(/ (org-user-idle-seconds) 60))))
|
||||
(time-subtract (current-time)
|
||||
(seconds-to-time (org-user-idle-seconds))))))))
|
||||
|
||||
(defun org-clock-in (&optional select)
|
||||
"Start the clock on the current item.
|
||||
If necessary, clock-out of the currently active clock.
|
||||
@ -773,9 +800,14 @@ the clocking selection, associated with the letter `d'."
|
||||
(interactive "P")
|
||||
(setq org-clock-notification-was-shown nil)
|
||||
(catch 'abort
|
||||
(let ((interrupting (marker-buffer org-clock-marker))
|
||||
ts selected-task target-pos (msg-extra ""))
|
||||
(unless org-clock-clocking-in
|
||||
(let ((interrupting (and (not org-clock-resolving-clocks-due-to-idleness)
|
||||
(marker-buffer org-clock-marker)))
|
||||
ts selected-task target-pos (msg-extra "")
|
||||
(left-over (and (not org-clock-resolving-clocks)
|
||||
org-clock-left-over-time)))
|
||||
(unless (or org-clock-clocking-in
|
||||
org-clock-resolving-clocks)
|
||||
(setq org-clock-left-over-time nil)
|
||||
(let ((org-clock-clocking-in t))
|
||||
(org-resolve-clocks))) ; check if any clocks are dangling
|
||||
(when (equal select '(4))
|
||||
@ -875,7 +907,15 @@ the clocking selection, associated with the letter `d'."
|
||||
(setq org-clock-effort (org-get-effort))
|
||||
(setq org-clock-total-time (org-clock-sum-current-item
|
||||
(org-clock-get-sum-start)))
|
||||
(setq org-clock-start-time (current-time))
|
||||
(setq org-clock-start-time
|
||||
(or (and left-over
|
||||
(y-or-n-p
|
||||
(format
|
||||
"You stopped another clock %d mins ago; start this one from then? "
|
||||
(/ (- (time-to-seconds (current-time))
|
||||
(time-to-seconds left-over)) 60)))
|
||||
left-over)
|
||||
(current-time)))
|
||||
(setq ts (org-insert-time-stamp org-clock-start-time
|
||||
'with-hm 'inactive))))
|
||||
(move-marker org-clock-marker (point) (buffer-base-buffer))
|
||||
@ -892,6 +932,11 @@ the clocking selection, associated with the letter `d'."
|
||||
(setq org-clock-mode-line-timer nil))
|
||||
(setq org-clock-mode-line-timer
|
||||
(run-with-timer 60 60 'org-clock-update-mode-line))
|
||||
(when org-clock-idle-timer
|
||||
(cancel-timer org-clock-idle-timer)
|
||||
(setq org-clock-idle-timer nil))
|
||||
(setq org-clock-idle-timer
|
||||
(run-with-timer 60 60 'org-resolve-clocks-if-idle))
|
||||
(message "Clock starts at %s - %s" ts msg-extra)
|
||||
(run-hooks 'org-clock-in-hook)))))))
|
||||
|
||||
@ -1066,6 +1111,9 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set."
|
||||
(when org-clock-mode-line-timer
|
||||
(cancel-timer org-clock-mode-line-timer)
|
||||
(setq org-clock-mode-line-timer nil))
|
||||
(when org-clock-idle-timer
|
||||
(cancel-timer org-clock-idle-timer)
|
||||
(setq org-clock-idle-timer nil))
|
||||
(setq global-mode-string
|
||||
(delq 'org-mode-line-string global-mode-string))
|
||||
(when org-clock-out-switch-to-state
|
||||
|
Loading…
Reference in New Issue
Block a user