(defun print-org-element()
  (message (format "%s" (org-element-type (org-element-at-point))))
  (message (org-element-property :title (org-element-at-point)))
  (message (org-element-property :parent (org-element-at-point))))

If caret is on headline, why this func can't print it's parent?


From the Org Element API at https://orgmode.org/worg/dev/org-element-api.html.

Unless point is on a headline, both functions indirectly return all parents of the value within the current section[footnote], through :parent property.

The footnote says:

Thus, org-element-at-point cannot return the parent of a headline. Nevertheless, headlines are context free elements: it is efficient to move to parent headline (e.g., with org-up-heading-safe) before analyzing it.

  • Weird. Why wouldn't they make it easy to access headlines parent? It seems like common use case. So is there a better way to find headlines parent, then searching backwards until i find string starting with less stars then the headline? – ame90 Nov 28 '18 at 19:24
  • You could also follow the suggestion and use org-up-heading-safe. There might be other functions which better fit your use case. – Marco Wahl Nov 28 '18 at 19:38
  • @ame90 The :parent property needs the whole parse tree (i.e., the value of (org-element-parse-buffer)) to make sense. – xuchunyang Nov 29 '18 at 13:36

org-element-at and org-element-context are often used in org source code because they give quite reliable, precise, and comprehensive information about the local structure of an org document.
Counting the occurrence of both in org.el gives the number 56 for org-20180115.

That precious information comes at a cost. The org-element parser is quite complicated and takes longer than a regexp-based search.

Therefore one needs to delimit the parsing for frequently run functions to a small local part of the document. The section headings are the most appropriate and most narrow boundaries for such parts.

The following slow variant my-org-element-at-point does not have the limitations of org-element-at-point but it is slower because it parses the whole Org buffer.

(defun my-org-element-neighborhood-p (element position &optional greater-element)
  "Return non-nil if POSITION is within the bounds of ELEMENT.
If GREATER-ELEMENT is non-nil the result is only non-nil
if ELEMENT is contained in GREATER-ELEMENT.
If the result is non-nil it is actually ELEMENT."
  (let ((b (org-element-property :begin element))
    (e (org-element-property :end element)))
     (<= b position)
     (>= e position)
     (or (null greater-element)
     (and (>= b (org-element-property :begin greater-element))
          (<= e (org-element-property :end greater-element))))

(defun my-org-element-at-point (&optional point)
  "Slow but more complete version of `org-element-at-point`."
  (unless point (setq point (point)))
  (let ((tree (org-element-parse-buffer))
    (org-element-map tree org-element-all-elements
      (lambda (el)
    (setq el-at (or (my-org-element-neighborhood-p el point el-at) el-at))))

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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