diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f3c1fa4f6..59578ad9e 100755 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,5 +1,30 @@ 2009-10-17 John Wiegley + * org-clock.el (org-find-open-clocks): New function that returns a + list of all open clocks in the given FILE. Note that each clock + it returns is a cons cell of the format (MARKER . START-TIME). + This "clock" value is used by several of the new clock module + utility functions. + (org-is-active-clock): New inline function which tests whether the + given clock value is the same as the currently active clock. + Returns non-nil if this is the case. + (org-with-clock-position): New macro that evaluates FORMS with + point in the buffer and at the position of the given clock. + Changes to the current clock are global. + (org-with-clock): New macro that evaluates FORMS with point in the + buffer and at the position of the given clock. However, changes + to the current clock are local and have no effect on the user's + active clock. This allows, for example, far any clock to be + cancelled without cancelling the active clock. + (org-clock-clock-in): New inline function that switches the active + clock to the given clock. If either the argument RESUME, or the + global `org-clock-in-resume', are non-nil, it will resume a clock + that was previously left open. + (org-clock-clock-out): New inline function that clocks out the + given clock value without affecting the currently active clock. + (org-clock-clock-cancel): New inline function that cancels the + given clock value without affecting the currently active clock. + * org-clock.el (org-clock-in): Before creating `org-clock-mode-line-timer', check to make sure an older timer is not currently running. diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 55185235b..5067d2f4a 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -495,6 +495,79 @@ Use alsa's aplay tool if available." (defvar org-clock-mode-line-entry nil "Information for the modeline about the running clock.") +(defun org-find-open-clocks (file) + "Search through the given file and find all open clocks." + (let ((buf (or (get-file-buffer file) + (find-file-noselect file))) + clocks) + (with-current-buffer buf + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "CLOCK: \\(\\[.*?\\]\\)$" nil t) + (push (cons (copy-marker (1- (match-end 1)) t) + (org-time-string-to-time (match-string 1))) clocks)))) + clocks)) + +(defsubst org-is-active-clock (clock) + "Return t if CLOCK is the currently active clock." + (and (org-clock-is-active) + (= org-clock-marker (car clock)))) + +(defmacro org-with-clock-position (clock &rest forms) + "Evaluate FORMS with CLOCK as the current active clock." + `(with-current-buffer (marker-buffer (car ,clock)) + (save-excursion + (save-restriction + (widen) + (goto-char (car ,clock)) + (beginning-of-line) + ,@forms)))) + +(put 'org-with-clock-position 'lisp-indent-function 1) + +(defmacro org-with-clock (clock &rest forms) + "Evaluate FORMS with CLOCK as the current active clock. +This macro also protects the current active clock from being altered." + `(org-with-clock-position ,clock + (let ((org-clock-start-time (cdr ,clock)) + (org-clock-total-time) + (org-clock-history) + (org-clock-effort) + (org-clock-marker (car ,clock)) + (org-clock-hd-marker (save-excursion + (outline-back-to-heading t) + (point-marker)))) + ,@forms))) + +(put 'org-with-clock 'lisp-indent-function 1) + +(defsubst org-clock-clock-in (clock &optional resume) + "Clock in to the clock located by CLOCK. +If necessary, clock-out of the currently active clock." + (org-with-clock-position clock + (let ((org-clock-in-resume (or resume org-clock-in-resume))) + (org-clock-in)))) + +(defsubst org-clock-clock-out (clock &optional fail-quietly at-time) + "Clock out of the clock located by CLOCK." + (let ((temp (copy-marker (car clock) + (marker-insertion-type (car clock))))) + (if (org-is-active-clock clock) + (org-clock-out fail-quietly at-time) + (org-with-clock clock + (org-clock-out fail-quietly at-time))) + (setcar clock temp))) + +(defsubst org-clock-clock-cancel (clock) + "Cancel the clock located by CLOCK." + (let ((temp (copy-marker (car clock) + (marker-insertion-type (car clock))))) + (if (org-is-active-clock clock) + (org-clock-cancel) + (org-with-clock clock + (org-clock-cancel))) + (setcar clock temp))) + (defun org-clock-in (&optional select) "Start the clock on the current item. If necessary, clock-out of the currently active clock.