Browse Source

State Notes: Allow capturing state notes in a drawer, LOGBOOK

Wanrong Lin writes:

     2. Can we put all of those state change history logging messages
        into a drawer like "STATE-HIST" (when the drawer is defined in
        org-drawers), so it is less intrusive in the file?

Yes we can.  This commit provides this functionality.  It introduces a
new drawer, LOGBOOK.  When the variable
`org-log-state-notes-into-drawer' is set, state change time stamps and
notes will go into this drawer, or another one specified by that
variable.
Carsten Dominik 16 years ago
parent
commit
f939957dc1
4 changed files with 106 additions and 41 deletions
  1. 6 0
      doc/ChangeLog
  2. 22 8
      doc/org.texi
  3. 6 0
      lisp/ChangeLog
  4. 72 33
      lisp/org.el

+ 6 - 0
doc/ChangeLog

@@ -1,3 +1,9 @@
+2009-02-12  Carsten Dominik  <carsten.dominik@gmail.com>
+
+	* org.texi (Tracking TODO state changes): Document storing state
+	change notes into a drawer.
+	(Agenda commands): Document the agenda command `z'.
+
 2009-02-11  Carsten Dominik  <carsten.dominik@gmail.com>
 
 	* org.texi (CSS support): Document CSS classes for section numbers.

+ 22 - 8
doc/org.texi

@@ -3416,14 +3416,22 @@ 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 maybe take 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{!} (for a time stamp) and @samp{@@} (for a note) in parenthesis
-after each keyword.  For example, with the setting
+@cindex drawer, for state change recording
+
+When TODO keywords are used as workflow states (@pxref{Workflow states}), you
+might want to keep track of when a state change occurred and maybe take a
+note about this change.  You can either record just a timestamp, or a
+timestamped note for a change.  These records will be inserted after the
+headline as an itemized list, newest first@footnote{See the variable
+@code{org-log-states-order-reversed}}.  When taking a lot of notes, you might
+want to get the notes out of a way into a drawer (@pxref{Drawers}).
+Customize the variable @code{org-org-log-state-notes-into-drawer} to get this
+behavior - the recommended drawer for this is called @code{LOGBOOK}.
+
+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{!} (for a time stamp) and @samp{@@} (for a note)
+in parenthesis after each keyword.  For example, with the setting
 
 @lisp
 (setq org-todo-keywords
@@ -6488,6 +6496,12 @@ key for this.
 @itemx S-@key{down}
 Decrease the priority of the current item.
 @c
+@kindex z
+@item z
+Add a note to the entry.  This note will be recorded, and then files to the
+same location where state change notes a put.  Depending on
+@code{org-log-state-notes-into-drawer}, this maybe inside a drawer.
+@c
 @kindex C-c C-a
 @item C-c C-a
 Dispatcher for all command related to attachments.

+ 6 - 0
lisp/ChangeLog

@@ -1,3 +1,9 @@
+2009-02-12  Carsten Dominik  <carsten.dominik@gmail.com>
+	* org.el (org-drawers): Add LOGBOOK to the default drawers.
+	(org-log-state-notes-into-drawer): New option.
+	(org-add-log-setup): Place the sate note marker into the drawer,
+	create drawer when necessary.
+
 2009-02-12  Carsten Dominik  <carsten.dominik@gmail.com>
 
 	* org.el (org-store-log-note): Fix note indentation when adding

+ 72 - 33
lisp/org.el

@@ -544,7 +544,7 @@ new-frame        Make a new frame each time.  Note that in this case
   :tag "Org Cycle"
   :group 'org-structure)
 
-(defcustom org-drawers '("PROPERTIES" "CLOCK")
+(defcustom org-drawers '("PROPERTIES" "CLOCK" "LOGBOOK")
   "Names of drawers.  Drawers are not opened by cycling on the headline above.
 Drawers only open with a TAB on the drawer line itself.  A drawer looks like
 this:
@@ -1791,12 +1791,33 @@ empty string.
 (unless (assq 'note org-log-note-headings)
   (push '(note . "%t") org-log-note-headings))
 
+(defcustom org-log-state-notes-into-drawer nil
+  "Non-nil means, insert state change notes and time stamps into a drawer.
+When nil, state changes notes will be inserted after the headline and
+any scheduling and clock lines, but not inside a drawer.  When t,
+notes
+The value of this variable should be the name of the drawer to use.
+LOGBOOK is proposed at the default drawer for this purpose, you can
+also set this to a string to define the drawer of your choice.
+
+If this variable is set, `org-log-state-notes-insert-after-drawers'
+will be ognored."
+  :group 'org-todo
+  :group 'org-progress
+  :type '(choice
+	  (const :tag "Not into a drawer" nil)
+	  (const :tag "LOGBOOK" "LOGBOOK")
+	  (string :tag "Other")))
+
 (defcustom org-log-state-notes-insert-after-drawers nil
   "Non-nil means, insert state change notes after any drawers in entry.
 Only the drawers that *immediately* follow the headline and the
 deadline/scheduled line are skipped.
 When nil, insert notes right after the heading and perhaps the line
-with deadline/scheduling if present."
+with deadline/scheduling if present.
+
+This variable will have no effect if `org-log-state-notes-into-drawer' is
+set."
   :group 'org-todo
   :group 'org-progress
   :type 'boolean)
@@ -9177,36 +9198,51 @@ When FINDPOS is non-nil, find the correct position for the note in
 the current entry.  If not, assume that it can be inserted at point.
 HOW is an indicator what kind of note should be created.
 EXTRA is additional text that will be inserted into the notes buffer."
-  (save-restriction
-    (save-excursion
-      (when findpos
-	(org-back-to-heading t)
-	(narrow-to-region (point) (save-excursion
-				    (outline-next-heading) (point)))
-	(looking-at (concat outline-regexp "\\( *\\)[^\r\n]*"
-			    "\\(\n[^\r\n]*?" org-keyword-time-not-clock-regexp
-			    "[^\r\n]*\\)?"))
-	(goto-char (match-end 0))
-	(when (and org-log-state-notes-insert-after-drawers
-		   (save-excursion
-		     (forward-line) (looking-at org-drawer-regexp)))
-	    (progn (forward-line)
-		   (while (looking-at org-drawer-regexp)
-		     (goto-char (match-end 0))
-		     (re-search-forward org-property-end-re (point-max) t)
-		     (forward-line))
-		   (forward-line -1)))
-	(unless org-log-states-order-reversed
-	  (and (= (char-after) ?\n) (forward-char 1))
-	  (org-skip-over-state-notes)
-	  (skip-chars-backward " \t\n\r")))
-      (move-marker org-log-note-marker (point))
-      (setq org-log-note-purpose purpose
-	    org-log-note-state state
-	    org-log-note-previous-state prev-state
-	    org-log-note-how how
-	    org-log-note-extra extra)
-      (add-hook 'post-command-hook 'org-add-log-note 'append))))
+  (let ((drawer (cond ((stringp org-log-state-notes-into-drawer)
+		       org-log-state-notes-into-drawer)
+		      (org-log-state-notes-into-drawer "LOGBOOK")
+		      (t nil))))
+    (save-restriction
+      (save-excursion
+	(when findpos
+	  (org-back-to-heading t)
+	  (narrow-to-region (point) (save-excursion
+				      (outline-next-heading) (point)))
+	  (looking-at (concat outline-regexp "\\( *\\)[^\r\n]*"
+			      "\\(\n[^\r\n]*?" org-keyword-time-not-clock-regexp
+			      "[^\r\n]*\\)?"))
+	  (goto-char (match-end 0))
+	  (cond
+	   (drawer
+	    (if (re-search-forward (concat "^[ \t]*:" drawer ":[ \t]*$")
+				   nil t)
+		(goto-char (match-end 0))
+	      (insert "\n:" drawer ":\n:END:")
+	      (beginning-of-line 0)
+	      (org-indent-line-function)
+	      (beginning-of-line 2)
+	      (org-indent-line-function)
+	      (end-of-line 0)))
+	   ((and org-log-state-notes-insert-after-drawers
+		 (save-excursion
+		   (forward-line) (looking-at org-drawer-regexp)))
+	    (forward-line)
+	    (while (looking-at org-drawer-regexp)
+	      (goto-char (match-end 0))
+	      (re-search-forward org-property-end-re (point-max) t)
+	      (forward-line))
+	    (forward-line -1)))
+	  (unless org-log-states-order-reversed
+	    (and (= (char-after) ?\n) (forward-char 1))
+	    (org-skip-over-state-notes)
+	    (skip-chars-backward " \t\n\r")))
+	(move-marker org-log-note-marker (point))
+	(setq org-log-note-purpose purpose
+	      org-log-note-state state
+	      org-log-note-previous-state prev-state
+	      org-log-note-how how
+	      org-log-note-extra extra)
+	(add-hook 'post-command-hook 'org-add-log-note 'append)))))
 
 (defun org-skip-over-state-notes ()
   "Skip past the list of State notes in an entry."
@@ -9288,7 +9324,10 @@ EXTRA is additional text that will be inserted into the notes buffer."
 	  (looking-at "[ \t]*")
 	  (setq ind (concat (match-string 0) "  "))
 	  (end-of-line 1)
-	  (while lines (insert "\n" ind (pop lines)))))))
+	  (while lines (insert "\n" ind (pop lines)))
+	  (message "Note stored")
+	  (org-back-to-heading t)
+	  (org-cycle-hide-drawers 'children)))))
   (set-window-configuration org-log-note-window-configuration)
   (with-current-buffer (marker-buffer org-log-note-return-to)
     (goto-char org-log-note-return-to))