% \iffalse meta-comment % % Copyright (C) 2026 by Hugo Heagren % --------------------------------------------------------------------------- % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2008-05-04 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Hugo Heagren. % % This work consists of the files countwords.dtx and countwords.ins % and the derived filebase countwords.sty. % % \fi % % \iffalse %<*driver> \ProvidesFile{countwords.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{countwords} %<*package> [2026/04/03 1.0 Exact word counts] % % %<*driver> \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage{listings} \lstset{ basicstyle=\MacroFont, keepspaces=true, numbers=left, xleftmargin=5.0ex, numberstyle=\scriptsize, } \usepackage{hyperref} \usepackage[date=year]{biblatex} \addbibresource{./references.bib} \EnableCrossrefs \CodelineNumbered \RecordChanges \begin{document} \DocInput{countwords.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % % \CheckSum{17} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{<+version+>}{<+date+>}{Converted to DTX file} % % \DoNotIndex{\newcommand,\newenvironment} % % \GetFileInfo{countwords.dtx} % \title{The \textsf{countwords} package} % \author{Hugo Heagren\thanks{The bulk of the actual code is in lua % and was written by Philipp Gesang \cite{gesang12_wordcount}.} \\ % \texttt{\href{mailto:hugo@heagren.com}{hugo@heagren.com}}} % \date{\fileversion~from \filedate} % % \maketitle % % \section{Introduction} % % This is a simple package for generating \emph{exact} wordcounts in % \LaTeX{} projects. It counts words, storing the value in a standard % \LaTeX{} counter, which can then be printed in the normal way. Word % counting can be paused and resumed, so you can skip certain % environments like mathematics, and multiple word counts can happen % in parallel (you could keep separate global and per-chapter counts, % for example). % % A note on \textsf{TeXcount} \cite{rødland_texcount}. % \textsf{TeXcount} is a popular way of counting words in \LaTeX{} % projects. It is an external script, which is run \emph{on} the % \LaTeX{} file, and produces an estimate of the number of words in % the final document. You can't use \textsf{TeXcount} to print a % wordcount for a document within that very document.\footnote{Well % you \emph{can} with some jiggerypokery, but it isn't pretty, and % this isn't what \textsf{TeXcount} was designed to do.} % \textsf{countwords} is a \LaTeX{} package which works \emph{within} % the document. \textsf{countwords} also prints \emph{exact} word % counts, because it counts the number of printed characters in the % final document as they are rendered; \textsf{TeXcount} prints a % reasonable estimate. % % \section{Usage} % % \textsf{countwords} requires Lua\LaTeX. Load as usual: % % \lstinputlisting{./countwords-load-example.tex} % % The package has one option, \texttt{threshold}, set with % \texttt{threshold=\(\langle{}number\rangle\)} This is the minimum number of % characters that a string must contain to count as a single word. So % setting it to 1 means that `I' and `a' count as words (as well as % anything longer); setting it to 3 means that `and' counts as a word, % but not `I', `a' or `as'. If unspecified it defaults to 1 (which is % usually the most sensible for prose writing). % % \textsf{countwords} stores all wordcounts in standard \LaTeX % counters, and does not create or manage these itself. So you must % create a counter to store the wordcount in: % % \lstinputlisting[firstnumber=last]{./countwords-counter-example.tex} % % \DescribeMacro{\countwordsstart\{\(\langle{}counter\rangle{}\)\}} % Issue this command to start counting words into % \(\langle{}counter\rangle{}\). After this, whenever \LaTeX{} encounters a string % of consecutive characters of longer than or equal to the threshold, % the \(\langle{}counter\rangle{}\) will increment by one. % % \DescribeMacro{\countwordsstop\{\(\langle{}counter\rangle{}\)\}} % Issue this command to stop counting words in % \(\langle{}counter\rangle{}\). After this, \textsf{countwords} will not alter the % value of \(\langle{}counter\rangle{}\). % % \section{Examples} % \subsection{Simple example} % \lstinputlisting{./countwords-simple-example.tex} % % \subsection{Printing count at the beginning} % % The \textsf{totcount} package \cite{koutavas_totcount} can be used % to print the eventual total of a counter before that total is % reached. % % \lstinputlisting{./countwords-totcount-example.tex} % % \subsection{Skipping maths} % % By starting and stopping the wordcount, things like display % mathematics can be skipped. Similar techniques could automatically % skip footnotes or citations. % \lstinputlisting{./countwords-maths-example.tex} % % \StopEventually{} % % \section{Implementation} % \iffalse %<*package> % \fi % % \begin{macrocode} \RequirePackage{luatexbase} \RequirePackage{luapackageloader} % \end{macrocode} % \subsection{Lua} % \begin{macrocode} \directlua{countwords = require("countwords")} % \end{macrocode} % \subsection{Options} % % \begin{macrocode} \DeclareKeys { threshold.code = \directlua{ countwords.set_threshold(\number#1) }, } \SetKeys{threshold=1} \DeclareUnknownKeyHandler{\PackageWarning{countwords}{Unknown option `#1'}} \ProcessKeyOptions % \end{macrocode} % \subsection{Add callback} % \begin{macrocode} \directlua{ luatexbase.add_to_callback( "pre_linebreak_filter", countwords.callback, "wordcount" ) }% % \end{macrocode} % \subsection{Document commands} % % % \begin{macro}{\countwordsstart} % \begin{macrocode} \def\countwordsstart#1{% \directlua{ countwords.enable_counter("#1") } } % \end{macrocode} % \end{macro} % % % \begin{macro}{\countwordsstop} % \begin{macrocode} \def\countwordsstop#1{% \directlua{ countwords.disable_counter("#1") } } % \end{macrocode} % \end{macro} % % % \printbibliography % % \iffalse % % \fi % % \Finale \endinput % \endinput % Local Variables: % mode: docTeX % TeX-master: t % End: