Stopped using wc-mode as it is not snappy anymore (as text writing usually is) with text document of 10k words. It appears that it counts the whole buffer after every change which seems to make it slow as logged here. A recent change was made to speed it up, but still produces considerable lag.

Partial Solution

There is a "solution" here, but it is so hard for me to implement it as I am not familiar with Lisp and inner workings of Emacs. There are two functions wc-buffer and wc-region, which are empty in the answer (below), for which I have no clue what should be in the function.

;; Function that counts words in buffer
(defun wc-buffer ()

;; Function that counts words in a region
(defun wc-region (rbeg rend)
(defvar-local a1 nil)
(defvar-local a2 nil)
(defvar-local curr-wc nil)
(defun init-function ()
    (setq curr-wc (wc-buffer))))

(defun wc-update-before (change-beg change-end)
  (setq pos1 (max 1 (1- change-beg)))
  (setq pos2 (min (point-max) (1+ change-end)))
  (setq a1 (wc-region pos1 pos2)))
(defun wc-update-after (change-beg change-end prev-len)
  (if (bound-and-true-p a1) 
        (setq pos1 (max 1 (1- change-beg)))
        (setq pos2 (min (point-max) (1+ change-end)))
        (setq a2 (wc-region pos1 pos2))
        (setq curr-wc (+ curr-wc (- a2 a1))))

(add-hook 'before-change-functions #'wc-update-before nil t) 
(add-hook 'after-change-functions #'wc-update-after nil t)
(setq inhibit-modification-hooks nil)


I ask for someone either to tell me explicitly what goes in these functions or suggest alternatives for counting words and not having lag while displaying them in the mode-line.


You can reproduce this by: installing wc-mode and enabling it and then when you have more than 10k words, you can expect (depending on your PC) quite some lag while typing. It's not snappy.

  • This sounds like a "please code something for me" pseudo-question - it lacks focus. What exactly is the question/problem? What does "lagged the hell out of my..." really mean? Please show your code - minimal recipe to reproduce the problem, starting from emacs -Q (no init file). Thx.
    – Drew
    Jan 4 '20 at 16:14
  • For time consuming functions that I use to obtain certain data for the mode-line (e.g., alphabetizing minor-mode lighter indicators), I use a two-step approach to deal with that: (1) record the most recent value and reuse that recorded value when certain criteria is met, instead of calculating anew; (2), if this-command is eq to last-command and the command is a memq of a predefined list of certain commands, then use the pre-recorded value from step 1 above. Flyspell uses step 2 if you are interested in seeing how that works.
    – lawlist
    Jan 4 '20 at 17:36
  • @drew I have edited the question to make it more clear. Please let me know if this is good enough?
    – Pandian Le
    Jan 5 '20 at 9:41
  • Much better, thanks. It still looks like a request to code up some functions, and it requires turning to another question for understanding. Can you show the code you tried, and pose a specific question about that, and can you make this question more standalone? This site is really better for specific Q&A, not discussion. You might want to post this more open-ended question on a site such as Reddit, where discussion etc. is invited.
    – Drew
    Jan 5 '20 at 18:13
  • @drew modified the question added code from the linked answer. No, I don't want to post it on reddit, I want direction in which I need to go. I want a solution. I will try using the suggestions provided by user12593215 and figure out how to implient it in the modeline I guess.
    – Pandian Le
    Jan 9 '20 at 20:18

Solution 1, add (setq wc-idle-wait 2) into ~/.emacs if you need get updated with the data in real time,

enter image description here

Please note wc-idle-wait should be set before loading wc-mode.el because of below code in wc-mode.el,

(setq wc-timer-tracker
       wc-idle-wait t
       '(lambda ()
          (when wc-mode
            (setq wc-buffer-stats (wc-mode-update))))))

Solution 2, do the calculation only before saving current buffer. But you need set wc-idle-wait to a bigger value first.

Here is sample setup (see my comment, you can do some further optimization inside before-save-hook),

(setq wc-idle-wait most-positive-fixnum)
(add-hook 'before-save-hook
          (lambda ()
            ;; you can check `buffer-file-name' or `major-mode' first
            (setq wc-buffer-stats (wc-mode-update))))

I think you can use count-words to implement the wc-buffer function and count-words-region to implement the wc-region function.

Like this:

(defun wc-buffer ()
    (count-words (point-min) (point-max)))

(defun wc-region (rbeg rend)
    (count-words-region rbeg rend))

See mode-line-idle, the readme shows an example of showing a word count in a way that's not blocking.

This allows you to add anything you like to your mode line in a way that doesn't block your workflow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.