0

C-x l wonderfully tells me how many lines there are on the page before and after the point. I was wondering whether it was possible to add to this the count of words, too:

Page has 107 lines (46 + 61), and 645 words (400 + 45)

My lines are typically full-paragraph long these days, so the line count is not that good in telling me where I am in the file. I have some really horrible ideas of how I could define a keyboard macro that would do this, abusing the count-words-region function, but I was hoping this would be an easy 1-min task for some emacs wizard. If so, please share. Otherwise, please ignore.

1 Answer 1

1

The cleanest way, I think, is to write your own functions to replace the ones that Emacs uses: count-lines-page (which is bound to C-x l) is a simple function that calls page--count-lines-page to do the heavy lifting. And as you guessed, count-words-region can be used to count the words. If you do C-h f page--count-lines-page you'll get the doc string of the function which allows you to click on the filename page.el to take you to the source code of the function. You can then compare it with the modified implementation below. Similarly for count-lines-page.

Here's the implementation:

(defun my/count-lines-and-words-page ()
  "Report number of lines and words on current page, and how many are before or after point."
  (interactive)
  (pcase-let ((`(,ltotal ,lbefore ,lafter ,wtotal ,wbefore ,wafter)
                   (my/page--count-lines-and-words-page)))
    (message (ngettext "Page has %d line (%d + %d), and %d word (%d + %d)"
                           "Page has %d lines (%d + %d), and %d words (%d + %d)"
                          (+ ltotal wtotal))
              ltotal lbefore lafter wtotal wbefore wafter)))

(defun my/page--count-lines-and-words-page ()
  "Return a list of line and word counts on the current page.
The list is on the form (LTOTAL LBEFORE LAFTER WTOTAL WBEFORE WAFTER), where LTOTAL is the
total number of lines on the current page, while LBEFORE and LAFTER
are the number of lines on the current page before and after
point, respectively, and similarly for WTOTAL, WBEFORE and WAFTER"
  (save-excursion
    (let ((opoint (point)))
      (forward-page)
      (beginning-of-line)
      (unless (looking-at page-delimiter)
        (end-of-line))
      (let ((end (point)))
        (backward-page)
        (list (count-lines (point) end)
              (count-lines (point) opoint)
              (count-lines opoint end)
              ;; Up to here everything is as in the original function.
              ;; Now add the new information.
              (count-words-region (point) end)
              (count-words-region (point) opoint)
              (count-words-region opoint end))))))

;; replace the old binding of `C-x l' with the new one.
(define-key ctl-x-map "l" #'my/count-lines-and-words-page)

The nice thing about incorporating the word counting in the same function that does the line counting, is that the regions (between the start of the page and the end of the page, between the start of the page and the current point, and between the current point and the end of the page) are all consistent and we did not have to reinvent that wheel. All we did is make the functions gather more information and report it.

Add that to your init file and say C-x l at some place in your file to test it.

1
  • wow. dankeschoen. this was more than one minute!
    – ivo Welch
    Commented Sep 16 at 16:44

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.