Hi friends, Here's a new function that counts lines, words, and characters in the region or the subtree at point. It prints a message like `count-words` does, like:
Subtree "Heading" has 7 line, 5 words, and 28 characters. Note that it does *not* count words in heading lines, planning lines, and drawers, so it gives a more useful count for the "prose" in the subtree. Here's the code: #+BEGIN_SRC elisp (defun ap/org-count-words () "If region is active, count words in it; otherwise count words in current subtree." (interactive) (if (use-region-p) (funcall-interactively #'count-words-region (region-beginning) (region-end)) (org-with-wide-buffer (cl-loop for (lines words characters) in (org-map-entries (lambda () (ap/org-forward-to-entry-content 'unsafe) (let ((end (org-entry-end-position))) (list (count-lines (point) end) (count-words (point) end) (- end (point))))) nil 'tree) sum lines into total-lines sum words into total-words sum characters into total-characters finally do (message "Subtree \"%s\" has %s lines, %s words, and %s characters." (org-get-heading t t) total-lines total-words total-characters))))) #+END_SRC It requires this supporting function: #+BEGIN_SRC elisp (defun ap/org-forward-to-entry-content (&optional unsafe) "Skip headline, planning line, and all drawers in current entry. If UNSAFE is non-nil, assume point is on headline." (unless unsafe ;; To improve performance in loops (e.g. with `org-map-entries') (org-back-to-heading)) (cl-loop for element = (org-element-at-point) for pos = (pcase element (`(headline . ,_) (org-element-property :contents-begin element)) (`(,(or 'planning 'property-drawer 'drawer) . ,_) (org-element-property :end element))) while pos do (goto-char pos))) #+END_SRC I think it's an improvement over the functions I've seen that do this. Hope someone finds it useful.