New attempt to get the logging code right.

Please read the manual sections about progress logging again.
This commit is contained in:
Carsten Dominik 2008-02-17 17:00:04 +01:00
parent 83a270d4d8
commit 4bbd7784fb
5 changed files with 173 additions and 186 deletions

View File

@ -1,3 +1,7 @@
2008-02-17 Carsten Dominik <dominik@science.uva.nl>
* org.el (org-local-logging): New function
2008-02-15 Carsten Dominik <dominik@science.uva.nl>
* org.el (org-todo): Make sure that LOGGING properties are
@ -5,10 +9,9 @@
2008-02-14 Carsten Dominik <dominik@science.uva.nl>
* org.el (org-log-progress): Renamed from `org-log-done'.
(org-log-done): New defvaralias.
* org.el:
(org-todo-keywords): Improve docstring.
(org-startup-options): Define the new startup option `logstate'.
(org-startup-options): Cleanup startup options.
(org-set-regexps-and-options): Process the "!" markers.
(org-todo): Respect the new logging stuff.
(org-log-note-how): New variable.

View File

@ -9,45 +9,17 @@
** Incompatible changes
- The variable `org-log-done' is obsolete. Please use
`org-log-progress' instead. For Emacs 21 users this is a
must, for the rest of us, `org-log-done' can still be used
as an alias.
- The variable `org-log-done' is not less complex.
- The in-buffer settings for logging have changed. Some
options no longer exists, some new ones have been added.
** Details
*** Changes to logging progress
There is now more control over which state changes are being
logged in what way. You can now request that the change to a
state does one of three options:
- No extre record of this state change.
- Record a time stamp only, without further user interaction
- Prompt for a note and record a time stamp.
First of all, the variable `org-log-done' is obsolete and
will be replaced by `org-log-progress', which is used in
exactly the same way but has a more appropriate
name. `org-log-done' only exists as a variable alias now.
`org-log-progress' may have these values:
- 'done Record a time stamp when the entry is done.
- t backward compatibility for `done', should not be used
- 'state Record a time stamp for each state change.
- list symbols indicating where a note should be taken,
may contain the symbols `done', `state', and
`clock-out'
However, the better way to configure this on a per-keyword
basis, using the marker characters "!" and "@". For example
#+TODO: TODO(t) STARTED(s!) WAIT(w@) | DONE(d!) CANCELLED(c@)
Now a time stamp will be recorded for STARTED, WAIT, DONE,
and CANCELLED. You will be prompted for an additional note
for WAIT and CANCELLED. Nothing will be recorded when you
switch to TODO.
logged in what way. Please read carefully the corresponding
sections in the manual.
*** Misc

51
TODO
View File

@ -1,32 +1,6 @@
-*- mode:org -*-
1. wenn org-log-done ist set, record a CLOSED time stamp.
when it is not set, don't.
logdone
nologdone
2. log progress is about state changes, clocking
(closed . timestamp)
(state . timestamp/note)
(clockout . note)
No, this is all too complex:
org-log-done : record the CLOSED timestamp or not
logdone nologdone
org-log-note-clock-out
should a note be taken when clocking out?
State logging only on a pre keyword basis.
Make sure that something like TODO(@) works correctly, i.e. that the
key is not obligatory.
Ideas for time estimates:
@ -36,37 +10,12 @@ Ideas for time estimates:
Maybe make a new keyword APPT for appointment, meaning that this is
something I need to attend, as opposed to something which is on that
day and not necessarily something where we need to be present. Not
sure about this.
Should we add this hierarchically? Should parents value be the summed
values of children? I guess not. No. Estimated times should be
atomic, belonging to the detailed entry. If people give estimated

100
org.el
View File

@ -1667,7 +1667,8 @@ taken from the (otherwise obsolete) variable `org-todo-interpretation'."
(repeat
(string :tag "Keyword"))))))
(defvar org-todo-keywords-1 nil)
(defvar org-todo-keywords-1 nil
"All TODO and DONE keywords active in a buffer.")
(make-variable-buffer-local 'org-todo-keywords-1)
(defvar org-todo-keywords-for-agenda nil)
(defvar org-done-keywords-for-agenda nil)
@ -1731,16 +1732,28 @@ Lisp variable `state'."
:type 'hook)
(defcustom org-log-done nil
"Non-nil means, recored a CLOSED timestamp when moving an entry to DONE.
"Non-nil means, record a CLOSED timestamp when moving an entry to DONE.
When equal to the list (done), also prompt for a closing note.
This can also be configured on a per-file basis by adding one of
the following lines anywhere in the buffer:
#+STARTUP: logdone
#+STARTUP: lognotedone
#+STARTUP: nologdone"
:group 'org-todo
:group 'org-progress
:type 'boolean)
:type '(choice
(const :tag "No logging" nil)
(const :tag "Record CLOSED timestamp" time)
(const :tag "Record CLOSED timestamp with closing note." note)))
;; Normalize old uses of org-log-done.
(cond
((eq org-log-done t) (setq org-log-done 'time))
((and (listp org-log-done) (memq 'done org-log-done))
(setq org-log-done 'note)))
;; FIXME: document
(defcustom org-log-note-clock-out nil
"Non-nil means, recored a note when clocking out of an item.
This can also be configured on a per-file basis by adding one of
@ -1786,19 +1799,32 @@ When nil, the notes will be orderer according to time."
:group 'org-progress
:type 'boolean)
(defcustom org-log-repeat t
"Non-nil means, prompt for a note when REPEAT is resetting a TODO entry.
When nil, no note will be taken.
(defcustom org-log-repeat 'time
"Non-nil means, record moving through the DONE state when triggering repeat.
An auto-repeating tasks is immediately switched back to TODO when marked
done. If you are not logging state changes (by adding \"@\" or \"!\" to
the TODO keyword definition, or recording a cloing note by setting
`org-log-done', there will be no record of the task moving trhough DONE.
This variable forces taking a note anyway. Possible values are:
nil Don't force a record
time Record a time stamp
note Record a note
This option can also be set with on a per-file-basis with
#+STARTUP: logrepeat
#+STARTUP: lognoterepeat
#+STARTUP: nologrepeat
You can have local logging settings for a subtree by setting the LOGGING
property to one or more of these keywords."
:group 'org-todo
:group 'org-progress
:type 'boolean)
:type '(choice
(const :tag "Don't force a record" nil)
(const :tag "Force recording the DONE state" time)
(const :tag "Force recording a note with the DONE state" note)))
(defcustom org-clock-into-drawer 2
"Should clocking info be wrapped into a drawer?
@ -4380,11 +4406,13 @@ we turn off invisibility temporarily. Use this in a `let' form."
("align" org-startup-align-all-tables t)
("noalign" org-startup-align-all-tables nil)
("customtime" org-display-custom-times t)
("logdone" org-log-done t)
("logdone" org-log-done time)
("lognotedone" org-log-done note)
("nologdone" org-log-done nil)
("lognoteclock-out" org-log-note-clock-out t)
("nolognoteclock-out" org-log-note-clock-out nil)
("logrepeat" org-log-repeat t)
("logrepeat" org-log-repeat state)
("lognoterepeat" org-log-repeat note)
("nologrepeat" org-log-repeat nil)
("constcgs" constants-unit-system cgs)
("constSI" constants-unit-system SI))
@ -4501,7 +4529,7 @@ means to push this value onto the list in the variable.")
note (and ex (string-match "@" ex))
time (or note (and ex (string-match "!" ex)))
key (and ex (substring ex 0 1)))
(if (equal key "@") (setq key nil))
(if (member key '("@" "!")) (setq key nil))
(push (cons kw (and key (string-to-char key))) kwsa)
(and (or note time)
(push (cons kw (if note 'note 'time))
@ -14448,6 +14476,9 @@ For calling through lisp, arg is also interpreted in the following way:
(let* ((match-data (match-data))
(startpos (point-at-bol))
(logging (save-match-data (org-entry-get nil "LOGGING" t)))
(org-log-done org-log-done)
(org-log-repeat org-log-repeat)
(org-todo-log-states org-todo-log-states)
(this (match-string 1))
(hl-pos (match-beginning 0))
(head (org-get-todo-sequence-head this))
@ -14548,6 +14579,7 @@ For calling through lisp, arg is also interpreted in the following way:
(not (member state org-done-keywords)))
(setq now-done-p (and (member state org-done-keywords)
(not (member this org-done-keywords))))
(and logging (org-local-logging logging))
(when (and (or org-todo-log-states org-log-done)
(not (memq arg '(nextset previousset))))
;; we need to look at recording a time and note
@ -14560,17 +14592,21 @@ For calling through lisp, arg is also interpreted in the following way:
(org-add-planning-info nil nil 'closed))
(when (and now-done-p org-log-done)
;; It is now done, and it was not done before
(org-add-planning-info 'closed (org-current-time)))
(org-add-planning-info 'closed (org-current-time))
(if (and (not dolog) (listp org-log-done)
(member 'done org-log-done))
(org-add-log-maybe 'done state 'findpos 'note)))
(when (and state dolog)
;; This is a non-nil state, and we need to log it
(org-add-log-maybe 'state state 'findpos dolog)))
;; Fixup tag positioning
(and org-auto-align-tags (not org-setting-tags) (org-set-tags nil t))
(run-hooks 'org-after-todo-state-change-hook)
(and (member state org-done-keywords) (org-auto-repeat-maybe))
(if (and arg (not (member state org-done-keywords)))
(setq head (org-get-todo-sequence-head state)))
(put-text-property (point-at-bol) (point-at-eol) 'org-todo-head head)
;; Do we need to trigger a repeat?
(when now-done-p (org-auto-repeat-maybe state))
;; Fixup cursor location if close to the keyword
(if (and (outline-on-heading-p)
(not (bolp))
@ -14584,6 +14620,26 @@ For calling through lisp, arg is also interpreted in the following way:
(save-excursion
(run-hook-with-args 'org-trigger-hook change-plist)))))))
(defun org-local-logging (property)
"Get logging settings from a property."
(let* (words w a)
;; directly set the variables, they are already local.
(setq org-log-done nil
org-log-repeat nil
org-todo-log-states nil)
(setq words (org-split-string property))
(while (setq w (pop words))
(cond
((setq a (assoc w org-startup-options))
(and (member (nth 1 a) '(org-log-done org-log-repeat))
(set (nth 1 a) (nth 2 a))))
((string-match "\\([a-zA-Z0-9]+\\)\\(([@!])\\)?" w)
(and (member (match-string 1 w) org-todo-keywords-1)
(match-end 2)
(push (cons (match-string 1 w)
(if (equal (match-string 2 w) "(@)") 'note 'time))
org-todo-log-states)))))))
(defun org-get-todo-sequence-head (kwd)
"Return the head of the TODO sequence to which KWD belongs.
If KWD is not set, check if there is a text property remembering the
@ -14670,7 +14726,7 @@ Returns the new TODO keyword, or nil if no state change should occur."
(defvar org-last-changed-timestamp)
(defvar org-log-post-message)
(defun org-auto-repeat-maybe ()
(defun org-auto-repeat-maybe (done-word)
"Check if the current headline contains a repeated deadline/schedule.
If yes, set TODO state back to what it was and change the base date
of repeating deadline/scheduled time stamps to new date.
@ -14680,19 +14736,20 @@ This function should be run in the `org-after-todo-state-change-hook'."
(aa (assoc last-state org-todo-kwd-alist))
(interpret (nth 1 aa))
(head (nth 2 aa))
(done-word (nth 3 aa))
(whata '(("d" . day) ("m" . month) ("y" . year)))
(msg "Entry repeats: ")
(org-log-done nil) ; ????????FIXME correct??
(org-log-done nil)
re type n what ts)
(when repeat
(if (eq org-log-repeat t) (setq org-log-repeat 'state))
(org-todo (if (eq interpret 'type) last-state head))
(when (and org-log-repeat
(not (memq 'org-add-log-note
(default-value 'post-command-hook))))
(or (not (memq 'org-add-log-note
(default-value 'post-command-hook)))
(eq org-log-note-purpose 'done)))
;; Make sure a note is taken;
(org-add-log-maybe 'done (or done-word (car org-done-keywords))
'findpos 'note))
(org-add-log-maybe 'state (or done-word (car org-done-keywords))
'findpos org-log-repeat))
(org-back-to-heading t)
(org-add-planning-info nil nil 'closed)
(setq re (concat "\\(" org-scheduled-time-regexp "\\)\\|\\("
@ -14888,7 +14945,7 @@ the current entry. If not, assume that it can be inserted at point."
(goto-char org-log-note-marker)
(org-switch-to-buffer-other-window "*Org Note*")
(erase-buffer)
(if (eq org-log-note-how 'time)
(if (memq org-log-note-how '(time state)) ; FIXME: time or state????????????
(org-store-log-note)
(let ((org-inhibit-startup t)) (org-mode))
(insert (format "# Insert note for %s.
@ -24672,7 +24729,8 @@ Does include HTML export options as well as TODO and CATEGORY stuff."
(if org-odd-levels-only "odd" "oddeven")
(if org-hide-leading-stars "hidestars" "showstars")
(if org-startup-align-all-tables "align" "noalign")
(cond ((eq t org-log-done) "logdone")
(cond ((eq org-log-done t) "logdone")
((equal org-log-done '(done)) "lognotedone")
((not org-log-done) "nologdone"))
(or (mapconcat (lambda (x)
(cond

161
org.texi
View File

@ -2911,8 +2911,9 @@ special faces for some of them. This can be done using the variable
Org-mode can automatically record a time stamp and possibly a note when
you mark a TODO item as DONE, or even each time you change the state of
a TODO item. This system is highly configurable, settings can be on a
per-file and even on a per-keyword basis. For information on how to
clock working time for a task, see @ref{Clocking work time}.
per-keyword basis and can be localized to a file or even a subtree. For
information on how to clock working time for a task, see @ref{Clocking
work time}.
@menu
* Closing items:: When was this entry marked DONE?
@ -2922,85 +2923,90 @@ clock working time for a task, see @ref{Clocking work time}.
@node Closing items, Tracking TODO state changes, Progress logging, Progress logging
@subsection Closing items
If you want to keep track of @emph{when} a certain TODO item was
finished, turn on logging with@footnote{The corresponding in-buffer
setting is: @code{#+STARTUP: logdone}. You may also set this for the
scope of a subtree by adding a @code{:LOGGING:} property with
one or more of the STARTUP logging keywords in the value. When set with
a property, all per-state settings are overruled.}
The most basic logging is to keep track of @emph{when} a certain TODO
item was finished. This is achieved with@footnote{The corresponding
in-buffer setting is: @code{#+STARTUP: logdone}}.
@lisp
(setq org-log-progress 'done)
(setq org-log-done 'time)
@end lisp
@noindent
Then each time you turn a TODO entry into DONE using either @kbd{C-c
C-t} in the Org-mode buffer or @kbd{t} in the agenda buffer, a line
@samp{CLOSED: [timestamp]} will be inserted just after the headline. If
you turn the entry back into a TODO item through further state cycling,
that line will be removed again. In the timeline (@pxref{Timeline}) and
in the agenda (@pxref{Weekly/Daily agenda}), you can then use the
@kbd{l} key to display the TODO items closed on each day, giving you an
overview of what has been done on a day. If you want to record a note
along with the timestamp, use@footnote{The corresponding in-buffer
setting is: @code{#+STARTUP: lognotedone}}
Then each time you turn an entry from an arbitrary TODO (not-done) state
into any of the DONE states using the dedicated commands like @kbd{C-c
C-t}, a line @samp{CLOSED: [timestamp]} will be inserted just after the
headline. If you turn the entry back into a TODO item through further
state cycling, that line will be removed again. If you want
to record a note along with the timestamp, use@footnote{The
corresponding in-buffer setting is: @code{#+STARTUP: lognotedone}}
@lisp
(setq org-log-progress '(done))
(setq org-log-done 'note)
@end lisp
@noindent
You will then be prompted for a note, and that note will be stored below
the entry with a @samp{Closing Note} heading.
In the timeline (@pxref{Timeline}) and in the agenda
(@pxref{Weekly/Daily agenda}), you can then use the @kbd{l} key to
display the TODO items with a @samp{CLOSED} timestamp on each day,
giving you an overview of what has been done.
@node Tracking TODO state changes, , Closing items, Progress logging
@subsection Tracking TODO state changes
When TODO keywords are used as workflow states (@pxref{Workflow
states}), you might want to keep track of when a state change occurred
and record a note about this change. With the setting@footnote{The
corresponding in-buffer setting is: @code{#+STARTUP: logstate}.}
and record a note about this change. Since it is normally too much to
record a note for every state, Org-mode expects configuration on a
per-keyword basis for this. This is achieved by adding special markers
@samp{!} and @samp{@@} in parenthesis behind each keyword. For example,
with the setting
@lisp
(setq org-log-progress 'state)
@end lisp
each state change will recorded with a time stamp. With the
setting@footnote{The corresponding in-buffer setting is:
@code{#+STARTUP: lognotestate}.}
@lisp
(setq org-log-progress '(state))
(setq org-todo-keywords
'((sequence "TODO(t)" "WAIT(w@@)" "|" "DONE(d!)" "CANCELED(c@@)")))
@end lisp
@noindent
each state change will prompt you for a note that will be attached to
the current headline. If you exit without writing anything, a time
stamp will still be recorded.
Very likely you do not want this verbose tracking all the time, so it is
probably better to configure this behavior on a per-keyword basis. You
can do this for a particular file with in-buffer settings, or globally
by configuring org-todo-keywords. For example, lets assume you are
tracking purchases in a particular file with the following TODO states:
you not only define global TODO keywords and fast access keys, but also
request that a time is recorded when the entry is turned into
DONE@footnote{It is possible that Org-mode will record two time stamps
when you are using both @code{org-log-done} and state change logging.
However, it will never prompt for two notes - if you have configured
both, the state change recording note will take precedence and cancel
the @samp{Closing Note}.}, and that a special note is recorded when
switching to WAIT or CANCELED.
You can use the exact same syntax for setting logging preferencs local
to a buffer:
@example
#+SEQ_TODO: TODO(t) ORDERED(o) INVOICE(i) PAYED(p) | RECEIVED(r)
#+STARTUP: lognotestate
#+SEQ_TODO: TODO(t) WAIT(w@@) | DONE(d!) CANCELED(c@@)
@end example
If you only need to take a time stamp or a note for some of the states,
mark those states with an additional @samp{!} or @samp{@@},
respectively, like this:
In order to define logging settings that are local to a subtree or a
single item, define a LOGGING property in this entry. Any non-empty
LOGGING property resets all logging settings to nil. You may then turn
on logging for this specific tree using STARTUP keywords like
@code{lognotedone} or @code{logrepeat}, as well as adding state specific
settings like @code{TODO(!)}. For example
@example
#+SEQ_TODO: TODO(t) ORDERED(o@@) INVOICE(i@@) PAYED(p!) | RECEIVED(r!)
* TODO Log each state with only a time
:PROPERTIES:
:LOGGING: TODO(!) WAIT(!) DONE(!) CANCELED(!)
:END:
* TODO Only log when switching to WAIT, and when repeating
:PROPERTIES:
:LOGGING: WAIT(@@) logrepeat
:END:
* TODO No logging at all
:PROPERTIES:
:LOGGING: nil
:END:
@end example
Then changing to a state PAYED or RECEIVED will record a time stamp, and
changing to the state ORDERED or INVOICE will also record a note.
@i{Note that specifying a per-keyword setting for logging causes the
corresponding #+STARTUP option to be ignored.}
If you would like to define fast access keys and per-state logging
indicators globally, you can use the same syntax in the variable
@code{org-todo-keywords}.
@node Priorities, Breaking down tasks, Progress logging, TODO items
@section Priorities
@ -4329,9 +4335,9 @@ actually switch the date like this:
You will also be prompted for a note@footnote{You can change this using
the option @code{org-log-repeat}, or the @code{#+STARTUP} options
@code{logrepeat} and @code{nologrepeat}.} that will be put under the
DEADLINE line to keep a record that you actually acted on the previous
instance of this deadline.
@code{logrepeat}, @code{lognoterepeat}, and @code{nologrepeat}.} that
will be put under the DEADLINE line to keep a record that you actually
acted on the previous instance of this deadline.
As a consequence of shifting the base date, this entry will no longer be
visible in the agenda when checking past dates, but all future instances
@ -4356,16 +4362,16 @@ 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}).
@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
location where the clock was last started. It also directly computes
the resulting time in inserts it after the time range as @samp{=>
HH:MM}. See the variable @code{org-log-progress} for the possibility to
record an additional note together with the clock-out time
stamp@footnote{The corresponding in-buffer setting is: @code{#+STARTUP:
lognoteclock-out}}.
HH:MM}. See the variable @code{org-log-note-clock-out} for the
possibility to record an additional note together with the clock-out
time stamp@footnote{The corresponding in-buffer setting is:
@code{#+STARTUP: lognoteclock-out}}.
@kindex C-c C-y
@item C-c C-y
Recompute the time interval after changing one of the time stamps. This
@ -7357,28 +7363,26 @@ variable is @code{org-startup-align-all-tables}, with a default value
align @r{align all tables}
noalign @r{don't align tables on startup}
@end example
Logging TODO state changes and clock intervals (variables
@code{org-log-progress} and @code{org-log-repeat}) can be configured using
these options.
Logging closing and reinstating TODO items, and clock intervals
(variables @code{org-log-done}, @code{org-log-note-clock-out}, and
@code{org-log-repeat}) can be configured using these options.
@cindex @code{logdone}, STARTUP keyword
@cindex @code{logging}, STARTUP keyword
@cindex @code{nologging}, STARTUP keyword
@cindex @code{lognotedone}, STARTUP keyword
@cindex @code{logstate}, STARTUP keyword
@cindex @code{lognotestate}, STARTUP keyword
@cindex @code{nologdone}, STARTUP keyword
@cindex @code{lognoteclock-out}, STARTUP keyword
@cindex @code{nolognoteclock-out}, STARTUP keyword
@cindex @code{logrepeat}, STARTUP keyword
@cindex @code{lognoterepeat}, STARTUP keyword
@cindex @code{nologrepeat}, STARTUP keyword
@example
logdone @r{record a timestamp when an item is marked DONE}
logging @r{alias for @code{logdone}}
nologging @r{don't record when items are marked DONE}
lognotedone @r{record timestamp and a note when DONE}
logstate @r{record a time stamp when a state change occurs}
lognotestate @r{record timestamp and a note when TODO state changes}
logrepeat @r{record a note when re-instating a repeating item}
nologrepeat @r{do not record when re-instating repeating item}
lognoteclock-out @r{record timestamp and a note when clocking out}
logdone @r{record a timestamp when an item is marked DONE}
lognotedone @r{record timestamp and a note when DONE}
nologdone @r{don't record when items are marked DONE}
logrepeat @r{record a time when reinstating a repeating item}
lognoterepeat @r{record a note when reinstating a repeating item}
nologrepeat @r{do not record when reinstating repeating item}
lognoteclock-out @r{record a note when clocking out}
nolognoteclock-out @r{don't record a note when clocking out}
@end example
Here are the options for hiding leading stars in outline headings. The
corresponding variables are @code{org-hide-leading-stars} and
@ -8652,3 +8656,4 @@ and contributed various ideas and code snippets.
@ignore
arch-tag: 7893d1fe-cc57-4d13-b5e5-f494a1bcc7ac
@end ignore
)