Emacs Org Mode: Adding a DONE Property When a TODO Task is Completed
We want to add a DONE property to a section when a TODO task is completed.
This is accomplished by placing the following code in init.el
:
(defun horizon/log-todo-completed-date (&rest ignore)
"Log TODO completion time in the property drawer under the key 'DONE'."
(when (and (string= (org-get-todo-state) "DONE")
(not (org-entry-get nil "DONE")))
(org-entry-put nil "DONE" (format-time-string (org-time-stamp-format t nil)))))
(add-hook 'org-after-todo-state-change-hook #'horizon/log-todo-completed-date)
In order to figure out how to add the desired functionality, one approach is to find out what happens when the S-<right>
key that
cycles through the TODO states is pressed. Place the cursor on a heading containing a TODO. Then type C-h k
for help on key
binding, and press the S-<right>
key. It runs org-shiftright
. It calls the org-todo
function. Looking at its source code shows
that the hook org-after-todo-state-change-hook
is called.
Another is to assume that some hook is called, and try to find the relevant hook using Emacs help and guess parts of the hook’s name.
Thirdly, one can use Edebug. Instrument the functions org-shiftright
and org-todo
by visiting them and type C-u C-M-x
for each of them. Change a TODO state using S-<right>
will take you to the debugger. Step through using SPC
, ?
for available commands.
Some more comments and hints:
The
&rest
keyword collects an arbitrary number of additional parameters in the list namedignore
in the code above.#'
is the sharp quote (or function quote), an abbreviation for the function form. It is essentially a version of quote (or'
) which enables byte-compilation. See https://endlessparentheses.com/get-in-the-habit-of-using-sharp-quote.html.Hooks are variables, thus their values and documentation can be obtained using
C-h v org—hook
.--
is the wildcard character.To develop, create a file called e.g.
develop.el
, add code to it, and evaluate the buffer usingC-c C-e
.Write out debug info using the
message
function, e.g.(message "Todo state: %s:" (org-get-todo-state))
.Special properties that should not be used as keys in the property drawer are described here: https://orgmode.org/manual/Special-Properties.html
Changing a function name and adding this hook doesn’t remove the function with the original name. Remove it using the
remove-hook
function which can be evaluated interactively.
Resources