18

I want to count how many words my LaTeX document has in it. I can do this by going to the website for the texcount package and using the web interface there. but that's not ideal.

I'd rather have some shortcut within emacs to just return number of words in a file (or ideally number of words in file and in all files called by \input or \include within the document). I have downloaded texcount script, but I don't know what to do with it. That is, I don't know where to put the .pl file, and how to call it within emacs.

That is: I want a keyboard shortcut for a shell command. And I want that shell command to run texcount on the current active buffer and return the total words in the minibuffer.

I'm using Ubuntu and emacs22, if that helps...

14

(defun latex-word-count ()
  (interactive)
  (shell-command (concat "/usr/local/bin/texcount.pl "
                         ; "uncomment then options go here "
                         (buffer-file-name))))

You may opt to put texcount.pl somewhere other than /usr/local/bin, just modify the code as appropriate if you do. This creates a new command "M-x latex-word-count", which will run texcount.pl on the current file (it will give the wrong result if you have not saved the file though). You can remove the semicolon and replace the filler text with any command line arguments you want to use, if any. You can bind this to a keyboard command with something like this in your .emacs:

(define-key latex-mode-map "\C-cw" 'latex-word-count)

The page which describes how to install texcount is here: texcount faq. Short version:

sudo cp texcount.pl /usr/local/bin/texcount.pl
or alternatively you could do as they recommend and simply name it texcount, and update the code appropriately.

  • If you want to include \input and \include files in the total, add "-inc " to your options. – Seamus Jul 2 '10 at 13:25
10

Here's a slightly nicer version of the above script (handles spaces in filenames, produces one-line output, etc...) The LaTeX hooks are for AuCTeX.

(defun my-latex-setup ()
  (defun latex-word-count ()
    (interactive)
    (let* ((this-file (buffer-file-name))
           (word-count
            (with-output-to-string
              (with-current-buffer standard-output
                (call-process "texcount" nil t nil "-brief" this-file)))))
      (string-match "\n$" word-count)
      (message (replace-match "" nil nil word-count))))
    (define-key LaTeX-mode-map "\C-cw" 'latex-word-count))
(add-hook 'LaTeX-mode-hook 'my-latex-setup t)
2

Short version: M-! texcount <file.tex> RET

I would simply use emacs included shell-command which is

M-! <cmd> RET

together with texcount (texcount.pl) which is installed with most latex distributions. While editing your document simply hit M-! enter texcount <tex-file> and hit return.

  • 1
    This was the quickest way to go for me as well. Thanks! – Jimi Oke Dec 28 '18 at 21:47
2

An easy combination of other solutions posted here would be:

(defun latex-word-count ()
   (interactive)
   (shell-command (concat "texcount " ; my latex installation includes texcount.pl
                       ; "uncomment then options go here, such as "
                       "-unicode "
                       "-inc "
                       (buffer-file-name))) ; better than typing path to current file
)

(define-key LaTeX-mode-map "\C-cw" 'latex-word-count)
2

For future reference, several of these answers would be improved by using the shell-quote-argument function to ensure that spaces and any other funny formatting in the file name would be handled correctly. For example, to improve on plgx's answer:

(defun latex-word-count ()
   (interactive)
   (shell-command (concat "texcount "
                       ; "uncomment then options go here, such as "
                       "-unicode "
                       "-inc "
                       (shell-quote-argument buffer-file-name))) 
;Now the buffer file name is sent correctly to the shell, 
;regardless of platform
)

(define-key LaTeX-mode-map "\C-cw" 'latex-word-count)
0

You can also use the built in M-x tex-count-words. To make a keyboard shortcut, add the following to .emacs

(add-hook 'latex-mode-hook
          (lambda () (local-set-key (kbd "C-c C-w") 'tex-count-words)))
0

I don't know if this would help anyone, but when I was writing my thesis I wanted to do two things; (1) count the number of words for the whole thesis (instead of a single chapter), and (2) use a custom counter script. The point for the latter was that it would avoid sections such as abstracts, declarations, etc. and only select the relevant chapters.

Count words from the master file

The solution here was simple; figure out whether the file we are in is the master one, otherwise, send that to texcount.

(defun latex-word-count-master ()
  (interactive)
  (if (eq TeX-master t)
      (setq master (buffer-file-name))
    (setq master (concat (expand-file-name TeX-master) ".tex")))
  (shell-command (concat "texcount "
                         "-dir "
                         "-unicode "
                         "-inc "
                         master)))

Use a custom script

I did that by adding a custom-tex-counter local variable to the included file pointing to the bash script that was responsible for word counting.

  • Declare the custom variable

    (defvar custom-tex-counter nil)
    (make-variable-buffer-local 'custom-tex-counter)
    (put 'custom-tex-counter 'safe-local-variable #'stringp)
    
  • Add the path in the local variables (end of .tex file)

    %%% Local Variables:
    %%% mode: latex
    %%% TeX-master: "../thesis"
    %%% custom-tex-counter: "../count_words -t"
    %%% End:
    
  • Putting it together with the above

    (defun latex-word-count-alt ()
      (interactive)
      (if (eq TeX-master t)
          (setq master (buffer-file-name))
        (setq master (concat (expand-file-name TeX-master) ".tex")))
      (if (not (eq custom-tex-counter nil))
          (shell-command (concat custom-tex-counter
                                 " "
                                 master))
        (shell-command (concat "texcount "
                               "-dir "
                               "-unicode "
                               "-inc "
                               master))))
    

For reference here's what my custom script looked like (don't forget to make it executable):

#!/usr/bin/bash

total='false'

while getopts 't' flag; do
  case "${flag}" in
    t) total='true' ;;
    ?) printf '\nUsage: %s: [-t] \n' $0; exit 2 ;;
  esac
done

shift $(($OPTIND - 1))

TOPATH=$(dirname "${1}")

CHAPTERS=$(while read -r chapter; do
               printf "%s%s.tex\n" "$TOPATH" "/$chapter";
           done < <(grep -Po "^[^%]\s?\\include{\K(Chapter|Appendix)[[:digit:]]+/(chapter|appendix)[[:digit:]]+" "${1}") \
           | paste -sd' ')

if [ "$total" == "false" ]; then
    texcount -unicode -inc $CHAPTERS
else
    texcount -unicode -total -inc $CHAPTERS
fi

Basically, the only thing this does is to grep the non-commented chapters and appendices from the master file and count the words there.

You can change the regex for each project to match the structure you are using but, if you consistently use the same structure, you can put the bash script somewhere in your path and make it a global variable in emacs instead of a local one.

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.