0

I saw the org-ql package quite recently and was sort of excited that it might be able to jquery / xpath style querying. But having a look at org-ql I could not quickly find a way of doing this with org-ql?

Is it possible to programmatically find the descendants of a heading with a certain name? E.g. if point is at a certain heading, how do I find the position of a heading which is a descendant of the first heading and has this name? What about if I just want to search the children?

Case 1

* Other
* Start <- cursor is here
** Child
*** descendant I want

I want a function (preferably one in a library)

(find-org-descendant "descendant I want")

That will return the position of this descendant

Case 2

Find children rather than descendants.

(find-org-child "Child")
2
  • I made some edits guessing at what you meant, but please review and make sure that I have not distorted what you meant. Can you also expand the last question ("What about the children?") - I don't know what you mean.
    – NickD
    Commented Mar 15, 2023 at 13:42
  • 1
    I've expanded a little. I wanted the position/mark rather than a path - mostly because I don't immediately know how to navigate org trees using paths. Regarding children - I meant how do I search children rather than descendants. I've made this clear and add some case studies
    – Att Righ
    Commented Mar 15, 2023 at 16:01

2 Answers 2

1

I am not sure if a library that does exactly this exists already, but you can easily implement such functionalities using the org-element-api.

Don't forget to study the API's function docstrings, and read the initial comment in org-element.el.

Then your functions could be implemented e.g. as follows:

;; it seems that we do not get contents when using the local parse
;; functions `org-element-at-point' or
;; `org-element-context'. Therefore we narrow to the `headline'
;; element and use `(org-element-parse-buffer)'
(defun find-org-descendant (regexp)
  (let ((descendant (org-element-map
                        (save-excursion
                          (save-restriction
                            ;; first walk up to top level
                            (while (/= (org-current-level) 1)
                              (org-up-heading-all 1))
                            (org-narrow-to-element)
                            (org-element-parse-buffer)))
                        'headline
                      (lambda (h) ; filter out headline
                        (when (string-match-p regexp (org-element-property :raw-value h))
                          h))
                      nil t))) ; look up the meaning of these args in docstring
    (org-element-property :begin descendant))) ; now get the position

(defun find-org-child (regexp)
  (let ((child (org-element-map
                   (save-excursion
                     (save-restriction
                       (while (/= (org-current-level) 1)
                         (org-up-heading-all 1))
                       (org-narrow-to-element)
                       (org-element-contents
                        (car
                         (org-element-contents
                          (org-element-parse-buffer))))))
                   'headline
                 ;; (apply-partially #'org-element-property :raw-value)
                 (lambda (h)
                   (when (string-match-p "child" (org-element-property :raw-value h))
                     h))
                 nil t 'headline)))
    (org-element-property :begin child)))
1
  • Thanks for the answer. Obviously this is very useful... a nice third party library would be great it is existed...
    – Att Righ
    Commented Mar 17, 2023 at 10:57
1

This came up again. I worked out how to create a predicate for this in org-ql.

The following finds all headings under the current heading.

(org-ql-defpred my-org-ql-at (point)
  "Search for entries precislely at point"
  :body (progn (message "point" point) (= (point) point)) )

(org-ql-query :select '(point) :from (current-buffer) :where `(ancestors (my-org-ql-at ,(save-excursion (org-back-to-heading) (point)))))

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.