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