1
0
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-11-26 07:33:39 +00:00

Implement a basic history system for recently clocked tasks.

Recently clocked tasks are now remembered as well as a default
task and an interrupted task.

There is no automatic clock-in yet.

Also, a number of bug fixes have sneaked into this patch,
sorry for the mess.
This commit is contained in:
Carsten Dominik 2008-04-25 08:18:49 +02:00
parent 2c2d172e10
commit add34418c8
3 changed files with 158 additions and 33 deletions

View File

@ -8,6 +8,21 @@
#+LINK_UP: index.html
#+LINK_HOME: http://orgmode.org
* Version 6.02a
** Details
*** Clock task history
Org now remembers the last 5 tasks that you clocked into, to
make it easier to clock back into a task after interrupting
it for another task.
- `C-u C-u C-c C-x C-i' (or `C-u C-u I' from the agenda) wil
clock into that task and mark it as current default task.
- `C-u C-c C-x C-i' (or `C-u I' from the agenda) will offer a
list of recently clocked tasks, including the default task,
for selection. `d' selects the default task, `i' selects
the task that was interrupted by the task that is currently
being clocked. `1',... selects a recent task. When you
select a task, you will be clocked into it.
* Version 6.02
** Overview

View File

@ -4493,7 +4493,11 @@ 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
this item, the multiple CLOCK lines will be wrapped into a
@code{:CLOCK:} drawer (see also the variable
@code{org-clock-into-drawer}).
@code{org-clock-into-drawer}). 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}.
@kindex C-c C-x C-o
@item C-c C-x C-o
Stop the clock (clock-out). The inserts another timestamp at the same
@ -4518,8 +4522,9 @@ Cancel the current clock. This is useful if a clock was started by
mistake, or if you ended up working on something else.
@kindex C-c C-x C-j
@item C-c C-x C-j
Jump to the entry that contains the currently running clock, an another
window.
Jump to the entry that contains the currently running clock. With a
@kbd{C-u} prefix arg, select the target task from a list of recently clocked
tasks.
@kindex C-c C-x C-d
@item C-c C-x C-d
Display time summaries for each subtree in the current buffer. This

View File

@ -93,6 +93,82 @@ The function is called with point at the beginning of the headline."
(defvar org-clock-heading "")
(defvar org-clock-start-time "")
(defvar org-clock-history
(list (make-marker) (make-marker) (make-marker) (make-marker) (make-marker))
"Marker pointing to the previous task teking clock time.
This is used to find back to the previous task after interrupting work.
When clocking into a task and the clock is currently running, this marker
is moved to the position of the currently running task and continues
to point there even after the task is clocked out.")
(defun org-clock-history-push (&optional pos buffer)
(let ((m (org-last org-clock-history)))
(move-marker m (or pos (point)) buffer)
(setq org-clock-history
(reverse (cdr (reverse org-clock-history))))
(while (member m org-clock-history)
(move-marker (car (member m org-clock-history)) nil))
(setq org-clock-history (cons m org-clock-history))))
(defun org-clock-select-task (&optional prompt)
"Select a task that recently was associated with clocking."
(interactive)
(let (sel-list rpl file task (i 0))
(save-window-excursion
(org-switch-to-buffer-other-window
(get-buffer-create "*Clock Task Select*"))
(erase-buffer)
(when (marker-buffer org-clock-default-task)
(insert (org-add-props "Default Task\n" nil 'face 'bold))
(setq s (org-clock-insert-selection-line ?d org-clock-default-task))
(push s sel-list))
(when (marker-buffer org-clock-interrupted-task)
(insert (org-add-props "Interrupted Task\n" nil 'face 'bold))
(setq s (org-clock-insert-selection-line ?i org-clock-interrupted-task))
(push s sel-list))
(insert (org-add-props "Recent Tasks\n" nil 'face 'bold))
(mapc
(lambda (m)
(when (marker-buffer m)
(setq i (1+ i)
s (org-clock-insert-selection-line
(string-to-char (number-to-string i)) m))
(push s sel-list)))
org-clock-history)
(shrink-window-if-larger-than-buffer)
(message (or prompt "Select task for clocking:"))
(setq rpl (read-char-exclusive))
(cond
((eq rpl ?q) nil)
((eq rpl ?x) nil)
((assoc rpl sel-list) (cdr (assoc rpl sel-list)))
(t (error "Invalid task choice %c" rpl))))))
(defun org-clock-insert-selection-line (i marker)
(when (marker-buffer marker)
(let (file cat task)
(with-current-buffer (marker-buffer marker)
(save-excursion
(goto-char marker)
(setq file (buffer-file-name (marker-buffer marker))
cat (or (org-get-category)
(progn (org-refresh-category-properties)
(org-get-category)))
task (org-get-heading 'notags))))
(when (and cat task)
(insert (format "[%c] %-15s %s\n" i cat task))
(cons i marker)))))
(defvar org-clock-default-task (make-marker)
"Marker pointing to the default task that should clock time.
The clock can be made to switch to this task after clocking out
of a different task.")
(defvar org-clock-interrupted-task (make-marker)
"Marker pointing to the default task that should clock time.
The clock can be made to switch to this task after clocking out
of a different task.")
(defun org-update-mode-line ()
(let* ((delta (- (time-to-seconds (current-time))
(time-to-seconds org-clock-start-time)))
@ -106,14 +182,39 @@ The function is called with point at the beginning of the headline."
(defvar org-clock-mode-line-entry nil
"Information for the modeline about the running clock.")
(defun org-clock-in ()
(defun org-clock-in (&optional select)
"Start the clock on the current item.
If necessary, clock-out of the currently active clock."
(interactive)
(org-clock-out t)
(let (ts)
If necessary, clock-out of the currently active clock.
With prefix arg SELECT, offer a list of recently clocked tasks to
clock into. When SELECT is `C-u C-u', clock into the current task and mark
is as the default task, a special task that will always be offered in
the clocking selection, associated with the letter `d'."
(interactive "P")
(let (ts selected-task)
;; Are we interrupting the clocking of a differnt task?
(if (marker-buffer org-clock-marker)
(progn
(move-marker org-clock-interrupted-task
(marker-position org-clock-marker)
(marker-buffer org-clock-marker))
(let ((org-clock-inhibit-clock-restart t))
(org-clock-out t)))
(move-marker org-clock-interrupted-task nil))
(cond
((equal select '(16))
(save-excursion
(org-back-to-heading t)
(move-marker org-clock-default-task (point))))
((equal select '(4))
(setq selected-task (org-clock-select-task "Clock-in on task: "))))
(save-excursion
(org-back-to-heading t)
(when (and selected-task (marker-buffer selected-task))
(set-buffer (marker-buffer selected-task))
(goto-char selected-task))
(org-clock-history-push)
(when (and org-clock-in-switch-to-state
(not (looking-at (concat outline-regexp "[ \t]*"
org-clock-in-switch-to-state
@ -127,7 +228,7 @@ If necessary, clock-out of the currently active clock."
(setq org-clock-heading "???")))
(setq org-clock-heading (propertize org-clock-heading 'face nil))
(org-clock-find-position)
(insert "\n") (backward-char 1)
(indent-relative)
(insert org-clock-string " ")
@ -258,19 +359,23 @@ If there is no running clock, throw an error, unless FAIL-QUIETLY is set."
(force-mode-line-update)
(message "Clock canceled"))
(defun org-clock-goto (&optional delete-windows)
"Go to the currently clocked-in entry."
(defun org-clock-goto (&optional select)
"Go to the currently clocked-in entry.
With prefix arg SELECT, offer recently clocked tasks."
(interactive "P")
(if (not (marker-buffer org-clock-marker))
(error "No active clock"))
(switch-to-buffer-other-window
(marker-buffer org-clock-marker))
(if delete-windows (delete-other-windows))
(goto-char org-clock-marker)
(org-show-entry)
(org-back-to-heading)
(org-cycle-hide-drawers 'children)
(recenter))
(let ((m (if select
(org-clock-select-task "Select task to go to: ")
org-clock-marker)))
(if (not (marker-buffer m))
(if select
(error "No task selected")
(error "No active clock")))
(switch-to-buffer (marker-buffer m))
(goto-char m)
(org-show-entry)
(org-back-to-heading)
(org-cycle-hide-drawers 'children)
(recenter)))
(defvar org-clock-file-total-minutes nil
"Holds the file total time in minutes, after a call to `org-clock-sum'.")
@ -666,9 +771,9 @@ the currently selected interval size."
(scope 'agenda)
(p1 (copy-sequence params))
file)
(plist-put p1 :tostring t)
(plist-put p1 :multifile t)
(plist-put p1 :scope 'file)
(setq p1 (plist-put p1 :tostring t))
(setq p1 (plist-put p1 :multifile t))
(setq p1 (plist-put p1 :scope 'file))
(org-prepare-agenda-buffers files)
(while (setq file (pop files))
(with-current-buffer (find-buffer-visiting file)
@ -767,17 +872,17 @@ the currently selected interval size."
(apply 'encode-time (org-parse-time-string ts)))))
(if te (setq te (time-to-seconds
(apply 'encode-time (org-parse-time-string te)))))
(plist-put p1 :header "")
(plist-put p1 :step nil)
(plist-put p1 :block nil)
(setq p1 (plist-put p1 :header ""))
(setq p1 (plist-put p1 :step nil))
(setq p1 (plist-put p1 :block nil))
(while (< ts te)
(or (bolp) (insert "\n"))
(plist-put p1 :tstart (format-time-string
(car org-time-stamp-formats)
(seconds-to-time ts)))
(plist-put p1 :tend (format-time-string
(car org-time-stamp-formats)
(seconds-to-time (setq ts (+ ts step)))))
(setq p1 (plist-put p1 :tstart (format-time-string
(car org-time-stamp-formats)
(seconds-to-time ts))))
(setq p1 (plist-put p1 :tend (format-time-string
(car org-time-stamp-formats)
(seconds-to-time (setq ts (+ ts step))))))
(insert "\n" (if (eq step0 'day) "Daily report: " "Weekly report starting on: ")
(plist-get p1 :tstart) "\n")
(org-dblock-write:clocktable p1)