1

I'm writing a function and I would like to operate on the current org heading and its content. For example:

* Head 1
  Text
** Head 2
   - Item 1
   - Item 2[p]
   - Item 3

If we look at the above text, with the location of point at [p], I would like to get the location right before "Head 2" and right after "Item 3".

Extra brownie points if I could pass in an optional parameter that would indicate the number of levels to include. So, 0 would do what I describe above, 1 would include "Head 1", etc.

Here's the code I have thus far:

(defun my-eval-org (&optional levels)
  "Evaluate the current Org mode heading and its content"
  (interactive "p")
  (if (eq major-mode 'org-mode)
      (save-excursion
        (while (and (> levels 0) (org-up-heading-safe)) ; Go up by 'levels' number of headings
          (setq levels (1- levels)))
        (let* ((element (org-element-at-point)) ; Get the org element at the current point
               (start (org-element-property :begin element)) ; The start point is the beginning of the element
               (end (org-element-property :end element))) ; The end point is the end of the element
          (my-eval-region start end)))
    (message "Not in org-mode")))

(defun my-eval-region (start end)
  "Evaluate the region from START to END and does something with it"
  (interactive "r")
  ;; Do something cool with the region contents
  )

The problem with this code is that if it runs within a list element, it will only evaluate the list element itself and not the enclosing heading.

Any help would be appreciated.

4
  • Please explain what "it will only evaluate the list element itself" means. Are you talking about what my-eval-region does? If so, you should realize that you have not provided its definition in your question, so we are left guessing.
    – NickD
    Commented Nov 21, 2023 at 21:44
  • my-eval-region processes the contents in some way that's not important to the question. I can add a stud implementation just for completeness.
    – oneself
    Commented Nov 22, 2023 at 9:03
  • That's what I guessed, but you should make it a practice to add that kind of info to the question (questions need to stand alone). Thanks for adding it in this case!
    – NickD
    Commented Nov 22, 2023 at 15:19
  • I ran your code with a dummy implementation of my-eval-region: I would suggest that you first eliminate the code that deals with levels and get it working in the levels=0 case. That will require navigating to the heading of the current level if you are not there already: org-back-to-heading will do that. Once that works, you can then test the loop to march up the hierarchy - the loop logic seems correct to me. One caveat is that org-up-heading-safe assumes that everything is visible: make sure to org-cycle your buffer to full visibility before you run the function.
    – NickD
    Commented Nov 22, 2023 at 15:24

1 Answer 1

1

My suggestions in the comment above amount to the following implementation of your function:

(defun my-eval-org (&optional levels)
  "Evaluate the current Org mode heading and its content"
  (interactive "p")
  (if (eq major-mode 'org-mode)
      (save-excursion
        (org-back-to-heading)    ;;; <--- the only change needed I think.
        (while (and (> levels 0) (org-up-heading-safe)) ; Go up by 'levels' number of headings
          (setq levels (1- levels)))
        (let* ((element (org-element-at-point)) ; Get the org element at the current point
               (start (org-element-property :begin element)) ; The start point is the beginning of the element
               (end (org-element-property :end element))) ; The end point is the end of the element
          (my-eval-region start end)))
    (message "Not in org-mode")))

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.