diff --git a/doc/org.texi b/doc/org.texi index e7da6e5af..90844d873 100644 --- a/doc/org.texi +++ b/doc/org.texi @@ -6012,6 +6012,7 @@ what to do with it. @table @kbd @orgcmd{C-c C-x C-i,org-clock-in} @vindex org-clock-into-drawer +@vindex org-clock-continuously @cindex property, LOG_INTO_DRAWER Start the clock on the current item (clock-in). This inserts the CLOCK keyword together with a timestamp. If this is not the first clocking of @@ -6022,9 +6023,10 @@ the setting of this variable for a subtree by setting a @code{CLOCK_INTO_DRAWER} or @code{LOG_INTO_DRAWER} property. When called with a @kbd{C-u} prefix argument, select the task from a list of recently clocked tasks. With two @kbd{C-u -C-u} prefixes, clock into the task at point and mark it as the default task. -The default task will always be available when selecting a clocking task, -with letter @kbd{d}.@* +C-u} prefixes, clock into the task at point and mark it as the default task; +the default task will then always be available with letter @kbd{d} when +selecting a clocking task. With three @kbd{C-u C-u C-u} prefixes, force +continuous clocking by starting the clock when the last clock stopped.@* @cindex property: CLOCK_MODELINE_TOTAL @cindex property: LAST_REPEAT @vindex org-clock-modeline-total @@ -6054,6 +6056,12 @@ HH:MM}. See the variable @code{org-log-note-clock-out} for the possibility to record an additional note together with the clock-out timestamp@footnote{The corresponding in-buffer setting is: @code{#+STARTUP: lognoteclock-out}}. +@orgcmd{C-c C-x C-I,org-clock-in-last} +@vindex org-clock-continuously +Reclock the last clocked task. With one @kbd{C-u} prefix argument, +select the task from the clock history. With two @kbd{C-u} prefixes, +force continuous clocking by starting the clock when the last clock +stopped. @orgcmd{C-c C-x C-e,org-clock-modify-effort-estimate} Update the effort estimate for the current clock task. @kindex C-c C-y @@ -6088,6 +6096,10 @@ 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. +@strong{Important:} note that both @code{org-clock-out} and +@code{org-clock-in-last} can have a global keybinding and will not +modify the window disposition. + @node The clock table, Resolving idle time, Clocking commands, Clocking work time @subsection The clock table @cindex clocktable, dynamic block @@ -6225,7 +6237,9 @@ would be @end example @node Resolving idle time, , The clock table, Clocking work time -@subsection Resolving idle time +@subsection Resolving idle time and continuous clocking + +@subsubheading Resolving idle time @cindex resolve idle time @cindex idle, resolve, dangling @@ -6292,6 +6306,18 @@ 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}. +@subsubheading Continuous clocking +@cindex continuous clocking +@vindex org-clock-continuously + +You may want to start clocking from the time when you clocked out the +previous task. To enable this systematically, set @code{org-clock-continuously} +to @code{t}. Each time you clock in, Org retrieves the clock-out time of the +last clocked entry for this session, and start the new clock from there. + +If you only want this from time to time, use three universal prefix arguments +with @code{org-clock-in} and two @kbd{C-u C-u} with @code{org-clock-in-last}. + @node Effort estimates, Relative timer, Clocking work time, Dates and Times @section Effort estimates @cindex effort estimates diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 34a4dcc7d..6e7bf5b7c 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -325,6 +325,12 @@ play with them." :version "24.1" :type 'boolean) +(defcustom org-clock-continuously nil + "Non-nil means to start clocking from the last clock-out time, if any." + :type 'boolean + :version "24.1" + :group 'org-clock) + (defcustom org-clock-total-time-cell-format "*%s*" "Format string for the total time cells." :group 'org-clock @@ -1054,7 +1060,10 @@ recently clocked tasks to clock into. When SELECT is \\[universal-argument] \\[universal-argument], \ clock into the current task and mark it as the default task, a special task that will always be offered in -the clocking selection, associated with the letter `d'." +the clocking selection, associated with the letter `d'. +When SELECT is \\[universal-argument] \\[universal-argument] \\[universal-argument], \ +clock in by using the last clock-out time as the start time +\(see `org-clock-continuously' to make this the default behavior.)" (interactive "P") (setq org-clock-notification-was-shown nil) (catch 'abort @@ -1073,6 +1082,11 @@ the clocking selection, associated with the letter `d'." (let ((org-clock-clocking-in t)) (org-resolve-clocks))) ; check if any clocks are dangling + (when (equal select '(64)) + ;; Set start-time to `org-clock-out-time' + (let ((org-clock-continuously t)) + (org-clock-in nil org-clock-out-time))) + (when (equal select '(4)) (setq selected-task (org-clock-select-task "Clock-in on task: ")) (if selected-task @@ -1191,7 +1205,8 @@ the clocking selection, associated with the letter `d'." (setq org-clock-total-time (org-clock-sum-current-item (org-clock-get-sum-start))) (setq org-clock-start-time - (or (and leftover + (or (and org-clock-continuously org-clock-out-time) + (and leftover (y-or-n-p (format "You stopped another clock %d mins ago; start this one from then? " @@ -1238,13 +1253,20 @@ the clocking selection, associated with the letter `d'." ;;;###autoload (defun org-clock-in-last (&optional arg) "Clock in the last closed clocked item. -When already clocking in, send an warning." +When already clocking in, send an warning. +With a universal prefix argument, select the task you want to +clock in from the last clocked in tasks. +With two universal prefix arguments, start clocking using the +last clock-out time, if any." (interactive "P") - (if arg (org-clock-select-task) - (org-clock-clock-in (cons (car org-clock-history) (current-time))) - (message "Now clocking in: %s (in %s)" - org-clock-current-task - (buffer-name (marker-buffer org-clock-marker))))) + (if (equal arg '(4)) (org-clock-in (org-clock-select-task)) + (let ((start-time (if (or org-clock-continuously (equal arg '(16))) + (or org-clock-out-time (current-time)) + (current-time)))) + (org-clock-clock-in (list (car org-clock-history)) nil start-time) + (message "Now clocking in: %s (in %s)" + org-clock-current-task + (buffer-name (marker-buffer org-clock-marker)))))) (defun org-clock-mark-default-task () "Mark current task as default task." @@ -1377,9 +1399,10 @@ line and position cursor in that line." (and (re-search-forward org-property-end-re nil t) (goto-char (match-beginning 0)))))))) +(defvar org-clock-out-time nil) ; store the time of the last clock-out (defun org-clock-out (&optional fail-quietly at-time) "Stop the currently running clock. -If there is no running clock, throw an error, unless FAIL-QUIETLY is set." +Throw an error if there is no running clock and FAIL-QUIETLY is nil." (interactive) (catch 'exit (when (not (org-clocking-p)) @@ -1388,7 +1411,8 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set." (setq frame-title-format org-frame-title-format-backup) (force-mode-line-update) (if fail-quietly (throw 'exit t) (error "No active clock"))) - (let (ts te s h m remove) + (let ((now (current-time)) ts te s h m remove) + (setq org-clock-out-time now) (save-excursion ; Do not replace this with `with-current-buffer'. (org-no-warnings (set-buffer (org-clocking-buffer))) (save-restriction @@ -1402,8 +1426,7 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set." (goto-char (match-end 0)) (delete-region (point) (point-at-eol)) (insert "--") - (setq te (org-insert-time-stamp (or at-time (current-time)) - 'with-hm 'inactive)) + (setq te (org-insert-time-stamp (or at-time now) 'with-hm 'inactive)) (setq s (- (org-float-time (apply 'encode-time (org-parse-time-string te))) (org-float-time (apply 'encode-time (org-parse-time-string ts)))) h (floor (/ s 3600)) @@ -1465,7 +1488,8 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set." (when clock-drawer (save-excursion (org-back-to-heading t) - (while (search-forward clock-drawer end t) + (while (and (< (point) end) + (search-forward clock-drawer end t)) (goto-char (match-beginning 0)) (org-remove-empty-drawer-at clock-drawer (point)) (forward-line 1)))))) @@ -1536,9 +1560,12 @@ UPDOWN tells whether to change 'up or 'down." (save-excursion ; Do not replace this with `with-current-buffer'. (org-no-warnings (set-buffer (org-clocking-buffer))) (goto-char org-clock-marker) - (delete-region (1- (point-at-bol)) (point-at-eol)) - ;; Just in case, remove any empty LOGBOOK left over - (org-remove-empty-drawer-at "LOGBOOK" (point))) + (if (save-excursion (move-beginning-of-line 1) + (looking-at (concat "^[ \t]*" org-clock-string))) + (progn (delete-region (1- (point-at-bol)) (point-at-eol)) + (org-remove-empty-drawer-at "LOGBOOK" (point))) + (message "Clock gone, cancel the timer anyway") + (sit-for 2))) (move-marker org-clock-marker nil) (move-marker org-clock-hd-marker nil) (setq global-mode-string diff --git a/lisp/org.el b/lisp/org.el index 40e723e41..7d664c9b8 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -17793,6 +17793,7 @@ BEG and END default to the buffer boundaries." (org-defkey org-mode-map "\C-c\C-x\C-t" 'org-toggle-time-stamp-overlays) (org-defkey org-mode-map "\C-c\C-x\C-i" 'org-clock-in) +(org-defkey org-mode-map "\C-c\C-x\C-I" 'org-clock-in-last) (org-defkey org-mode-map "\C-c\C-x\C-o" 'org-clock-out) (org-defkey org-mode-map "\C-c\C-x\C-j" 'org-clock-goto) (org-defkey org-mode-map "\C-c\C-x\C-x" 'org-clock-cancel)