If we have

* Header 1
Some contents.

Is there a way to programmatically kill the contents of Header 1 so that it remains like:

* Header 1



There isn't a command for deleting the subtree (i.e., the head line and all its contents), but there is a command to mark it. We can use that to get what you want:

(defun clear-subtree ()
  (org-mark-subtree) ;; mark the current subtree
  (forward-line) ;; move point forward, so the headline isn't in the region
  (delete-region (region-beginning) (region-end)) ;; delete the rest
| improve this answer | |
  • 1
    Maybe, you could mention that org-mark-subtree puts point at the start of the current subtree (i.e., on the headline) and mark at the end. – Tobias Jan 25 '18 at 22:44
  • And that org-mark-subtree is by default binded to C-c @, which is very useful. – kotchwane Mar 8 at 11:34

There are many ways of removing the contents of a headline. Taylor gave you already a straight-forward text editing method which is good and which you should perhaps accept as an answer.

But there is more. Orgmode has a well defined syntax and also routines for parsing and printing.

So one way to change the contents of your org buffer is:

  • parsing the org buffer via org-element-parse-buffer
  • search the parse tree for the element you want to change via org-element-map
  • modify the element in the parse data
  • print out the parse data via org-element-interpret-data

I give you an example for your special case of removing the content of Header 1. The following code returns a string with the text of buffer test.org modified with the contents of Header 1 removed.

(with-current-buffer "test.org"
  (let* ((data (org-element-parse-buffer)))
    (org-element-map data 'headline
      (lambda (el)
    (when (equal
           (car-safe (org-element-property :title el))
           "Header 1")
      (setf (nthcdr 2 el) nil) ;; Here we remove the contents from this headline.
    (org-element-interpret-data data)))

Which method you should use strongly depends on the actual use-case.

| improve this answer | |
  • You define the local variable mylist, but you don't actually use it anywhere? – Tyler Jan 25 '18 at 21:49
  • @Tyler Thanks for the hint. mylist was for debugging only. It was a walking dead;-). – Tobias Jan 25 '18 at 22:34

It seems you can use org-map-entries to do this as well:

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

   (lambda ()
     (let ((name (nth 4 (org-heading-components))))
       (if (string= name "Header 1")
             (delete-region (region-beginning) (region-end))
       )) MATCH SCOPE SKIP))

* Header 1
Content of header 1 
* Header 2
Content of header 2

If you run the source code block with C-c C-c, it will remove Content of header 1 under Header 1.

| improve this answer | |

Another trick is to find the bounds of what you want to clear, and then move to the END and keep deleting the previous character until the value of point is smaller than the value of START. You may also want to preserve metadata information by setting the optional argument to a non-nil value.

(defun clear-subtree (&optional metadata)
  (let (start)
      (org-back-to-heading t)
      (if metadata
          (org-end-of-meta-data nil)
        (forward-line 1))
      (setq start (point))
      (org-end-of-subtree t)
      (while (>= (point) start)
        (delete-char -1)))))
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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