7

Let's say I have an org-mode file at ~/myorg.org, looking like this:

* TODO My TODO list
** TODO Play games
** TODO Build a boat
** DONE Do something else

Now I want to modify this document using org-element. Let's say I want to change all TODO items to DONE. I thought something like this would work:

(with-current-buffer (find-file-noselect "~/myorg.org") 
  (org-element-map (org-element-parse-buffer) 'headline
    (lambda (h)
      (org-element-put-property h :todo-keyword "DONE")))
  (save-buffer))

The structure returned from org-element-map seems fine, but the code doesn't modify the file. Do I have to replace the whole buffer text using org-element-interpret-data, or is there some other way?

1

2 Answers 2

7

The org-element-put-property command does not modify the buffer content, it just returns the new element.

I would approach your use case differently: call save-excursion, then jump to the top of the buffer (or region, etc). Move forward using outline-next-heading. At each heading you can call org-entry-is-todo-p and (org-todo 'done) to mark each one done. Then save the buffer.

More generally: if you want to use the org-element API to apply changes, I think you are correct that you would need to call org-element-interpret-data to convert the updated AST back to text and then replace the buffer content. See http://orgmode.org/worg/dev/org-element-api.html.

1
  • 1
    Yes in the specific example that would work. I'm more interested in generally modifying a file's content using the org-element API. I'll try to update the question to reflect that. Feb 24, 2017 at 15:49
2

Here is one solution using org-map-entries. If you do C-c C-c on the source code block it will change all TODO entries to DONE in the current buffer. One caveat is that if you have DONE with @ (e.g., "DONE(d@)") in org-todo-keywords, then the last entry's change will invoke note taking for the change, and I'm not sure how to suppress it. I guess pressing C-c C-k once is not too bad.

#+BEGIN_SRC emacs-lisp :results none
(let ((MATCH "/+TODO")
      (SCOPE nil)
      (SKIP nil)
      (spacing nil))

  (org-map-entries
   (lambda () 
       (org-todo 'done))
    MATCH SCOPE SKIP))
#+END_SRC

* TODO My TODO list
** TODO Play games
** TODO Build a boat
** DONE Do something else

Your Answer

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

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