3

Description

When calling org-todo from a function, e.g., via org-map-entries or search-forward (see example code below), then the todo state change logging is only applied to one matched heading.

For example, calling one of these mark-done functions:

(defun mark-done ()
  (interactive)
  (org-map-entries
   (lambda ()
      (org-todo "DONE"))
   "/TODO" 'file))
(defun mark-done ()
  (interactive)
  (let ((case-fold-search nil))
    (goto-char (point-min))
    (while (search-forward " TODO " nil t)
      (org-todo "DONE"))))

On this file:

#+TODO: TODO(t) WAIT(w) | DONE(d!)
* WAIT W1
  SCHEDULED: <2000-01-01 Sat>

* TODO T1
  SCHEDULED: <2000-01-01 Sat>

* WAIT W2
  SCHEDULED: <2000-01-01 Sat>

* TODO T2
  SCHEDULED: <2000-01-01 Sat>

Results in this file (State line not added to T1, only added to T2):

#+TODO: TODO(t) WAIT(w) | DONE(d!)
* WAIT W1
  SCHEDULED: <2000-01-01 Sat>

* DONE T1
  CLOSED: [2000-01-01 Sat 00:01] SCHEDULED: <2000-01-01 Sat>

* WAIT W2
  SCHEDULED: <2000-01-01 Sat>

* DONE T2
  CLOSED: [2000-01-01 Sat 00:01] SCHEDULED: <2000-01-01 Sat>

  - State "DONE"       from "TODO"       [2000-01-01 Sat 00:01]

This could be a bug, but my (e)lisp knowledge is basically nil, so I am not sure how to investigate it further or if I am calling the function incorrectly.


Question

How do you make org-todo apply todo state change logging to all headings, when called from a function? I.e., how can you replicate the behavior of manually calling org-todo on each headline?


Version

This was run as emacs -Q in:

  • GNU Emacs 26.1 (build 1, x86_64-pc-linux-gnu, X toolkit, Xaw scroll bars) of 2019-03-25.
  • Org mode version 9.1.9 (release_9.1.9-65-g5e4542 @ /usr/share/emacs/26.1/lisp/org/.

1 Answer 1

3

You do it by customizing org-log-into-drawer which you have presumably done. The problem is that your function has a bug: it contains two calls to org-map-entries. Try the following function instead:

(defun mark-done ()
  (interactive)
  (org-map-entries
   (lambda ()
      (org-todo "DONE"))
   "/TODO" 'file))

OOPS: There was an extra paren at the end of the function - sorry about that.

EDIT: I could have sworn it worked for me, but I just tried it again and I think you are right. The problem seems to be that org-todo adds the logging info by calling org-add-log-setup with some information which is stored (in global variables!) and then adds org-add-log-note to post-command-hook - but the latter is only executed at the end of a command, e.g. at the end of org-todo when it is called interactively, but not when it is called e.g. from org-map-entries. It is only executed at the end of your mark-done, so only the last entry gets logging information: any previous entries have been overwritten.

I think this qualifies as a bug, so it's worth reporting to the mailing list, but I'm not sure it will be easy to fix.

In the meantime, I think you can work around the problem by calling org-add-log-note explicitly (although that looks fraught with peril, it seems to work in my small experiments):

(defun mark-done ()
  (interactive)
  (org-map-entries
   (lambda ()
     (progn
      (org-todo "DONE")
      (org-add-log-note)))
   "/TODO" 'file))
3
  • Thanks for spotting that bug! It was not present in my original function though so the behavior persist. What do you mean with org-log-into-drawer? I do modify it usually to t, but used the default nil when asking this question, but it does not fix this problem?
    – Klorax
    Apr 8, 2019 at 6:52
  • Seems to be working fine, thanks! What perils are you worried could ruin this?
    – Klorax
    Apr 9, 2019 at 15:04
  • Looking at org-add-log-note there's all sorts of UI elements in there. I was worried that depending on settings, you might get pop-ups that ask for additional information.
    – NickD
    Apr 9, 2019 at 16:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.