One thing I need pretty often is to be able to count Org mode headlines in the subtree I’m in. It’s a bit surprising that Org does not know how to do that, but this is Emacs, so fixing it should be very easy, right? Indeed, it is – although it’s probably worth noting that the problem isn’t well-defined. Do I want to only count direct children of the current headline or all its descendants? At first I decided that what I need is the former, but then it dawned on me – why not both? And that way, the following command was born.
(defun org-count-headlines ()
"Count Org Mode headlines one level below the current one."
(interactive)
(if-let* ((level (org-current-level)))
(save-excursion
(save-restriction
(org-narrow-to-subtree)
(message "%s has %s direct level %s children and %s descendants"
(org-get-heading t t t t)
(1- (how-many (org-headline-re (1+ level))
(point-min) (point-max)))
(1+ level)
(1- (how-many org-outline-regexp-bol
(point-min) (point-max))))))
(message "%s level 1 headlines and %s total headlines"
(how-many (org-headline-re 1)
(point-min) (point-max))
(how-many org-outline-regexp-bol
(point-min) (point-max)))))
It’s a very simple – even simplistic – one, with maybe one or two non-obvious points. The org-current-level function returns nil when the point is before the first headline in the file, so I used if-let* to avoid trying to perform arithmetical operations on nil (which would result in an error). Another thing worth mentioning is the org-headline-re function, which – combined with org-narrow-to-subtree and how-many – allows to count headlines on level not exceeding its parameter without parsing the Org syntax. On the other hand, org-outline-regexp-bol matches a headline on any level.
That’s it for today, happy counting!
CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryOrgMode