From c298d4d9179fd47c8a610670a8d8a9b4a2dc3c83 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Tue, 28 Sep 2010 16:03:57 +0000 Subject: new latex package everyhook (27sep10) git-svn-id: svn://tug.org/texlive/trunk@19935 c570f23f-e606-0410-a88d-b1316a301751 --- .../source/latex/everyhook/everyhook.dtx | 564 +++++++++++++++++++++ 1 file changed, 564 insertions(+) create mode 100644 Master/texmf-dist/source/latex/everyhook/everyhook.dtx (limited to 'Master/texmf-dist/source/latex/everyhook') diff --git a/Master/texmf-dist/source/latex/everyhook/everyhook.dtx b/Master/texmf-dist/source/latex/everyhook/everyhook.dtx new file mode 100644 index 00000000000..bc02d75ff2a --- /dev/null +++ b/Master/texmf-dist/source/latex/everyhook/everyhook.dtx @@ -0,0 +1,564 @@ +% \iffalse The license starting three lines down applies to this file +%<*batchfile> +{\catcode`\^^M13 \catcode`@11 \gdef\eh@preamble{ +Copyright (C) 2010 by Stephen Checkoway + +This file 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 2005/12/01 or later. + +This work has the LPPL maintenance status 'maintained'. + +The Current Maintainer of this work is Stephen Checkoway. + +This work consists of everyhook.dtx and the derived file +everyhook.sty. +}} +% +% +%<*package> +\NeedsTeXFormat{LaTeX2e}[1999/12/01] +\RequirePackage{svn-prov} +\ProvidesPackageSVN + {$Id: everyhook.dtx 9 2010-09-27 07:39:15Z steve $} + [v1.0 \revinfo\ Hooks for low level TeX everyX primitives.] +% +%<*batchfile> +\begingroup +\input docstrip +\keepsilent +\usedir{tex/latex/everyhook} +\expandafter\preamble\eh@preamble +\endpreamble +\askforoverwritefalse +\generate{\file{\jobname.sty}{\from{\jobname.dtx}{package}}} +\endgroup +% +%<*driver> +\documentclass{ltxdoc} +\usepackage{fixltx2e} +\usepackage{etoolbox} +\usepackage[osf]{mathpazo} +\usepackage[scaled=0.86]{berasans} +\usepackage[scaled=1.03]{inconsolata} +\usepackage[T1]{fontenc} +\usepackage{microtype} +\usepackage[margin=1.5in]{geometry} +\usepackage{everyhook} +\usepackage{enumitem} +\usepackage[pdfborder={0 0 0}]{hyperref} +\usepackage{ifpdf} +\usepackage{listings} +\usepackage{lipsum} +\begingroup +\catcode`\^^09\active +\gdef\obeytabs{% +\catcode`\^^09\active +\def^^09{\ \ \ \ \ \ \ \ }% +} +\endgroup +\makeatletter +\patchcmd\macrocode{\@vobeyspaces}{\@vobeyspaces\obeytabs}{}{\undefined} +\makeatother + +\CheckSum{190} +\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 \~} + +\DoNotIndex{\csdef,\cslet,\csname,\csuse,\def,\endcsname,\endinput, +\every,\expandafter,\gdef,\global,\ifcsdef,\ifcsempty,\ifdefequal, +\letcs,\newrobustcmd,\newtoks,\PackageError,\protect,\RequirePackage, +\space,\the,\undef} + +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\GetFileInfo{\jobname.sty} +\title{The \textsf{\jobname} package\thanks{This document +corresponds to \textsf{\jobname}~\fileversion, dated \filedate.}} +\author{Stephen Checkoway\\\texttt{s@cs.ucsd.edu}} + +\lstset{language=[LaTeX]TeX,basicstyle=\ttfamily, +texcsstyle=*\normalfont\bfseries, +moretexcs={paragraph,RequirePackage},xleftmargin=\parindent} + +\renewcommand*\arg[1]{\textsf{\{#1\}}} +\makeatletter +\renewcommand*\meta@font@select{\normalfont\itshape} +\begin{document} +\maketitle + +\begin{abstract} +The \textsf{\jobname} package takes control of the six \TeX\ +token parameters \cs{everypar}, \cs{everymath}, \cs{everydisplay}, +\cs{everyhbox}, \cs{everyvbox}, and \cs{everycr}. Real hooks for +each of these can be installed using a stack like interface. For +compatibility with \LaTeX\ standard classes and packages, each of +the \cs{everyX} token lists can be set without interfering with the +hooks. +\end{abstract} +\tableofcontents + +\section{Introduction} +\TeX\ contains nine token parameters, seven of which are inserted +into the current list at various times. Quoting from \textit{The +\TeX book}, the seven token parameters of interest are\footnote{The remaining two +token parameters are \cs{output} and \cs{errhelp}.} +\begin{description}[labelindent=1em, noitemsep] +\item{\cs{everypar}\enskip} tokens to insert when a paragraph begins, +\item{\cs{everymath}\enskip} tokens to insert when math in text begins, +\item{\cs{everydisplay}\enskip} tokens to insert when display math begins, +\item{\cs{everyhbox}\enskip} tokens to insert when an hbox begins, +\item{\cs{everyvbox}\enskip} tokens to insert when a vbox begins, +\item{\cs{everyjob}\enskip} tokens to insert when the job begins, and +\item{\cs{everycr}\enskip} tokens to insert after every \cs{cr} or +nonredundant \cs{crcr}. +\end{description} +Of these, \cs{everyjob} is not very useful outside of INITEX and so +it won't be considered further. + +The remaining six token parameters can be used to great effect. For +example, the \cs{everypar} is used in \cs{paragraph} to set the title +of the paragraph inline allowing constructions like\\ +\indent\hbox to.45\textwidth{% +\begin{lstlisting}[boxpos=b] +\paragraph{Paragraph title.} + +A blank line followed by +the rest of the paragraph. +\end{lstlisting}\hfil +} +\hfill +\parbox[b]{.45\textwidth}{ +\paragraph{Paragraph title.} + +\strut A blank line followed by the rest of the paragraph. +\\[\baselineskip] +}\\[\baselineskip] +which work properly rather than starting a new paragraph due to the +blank line. + +Similarly, \cs{everymath} and \cs{everydisplay} are used by the +\LaTeX\ kernel to set up math fonts. + +Using the \TeX\ primitives directly has the major downside that they +cannot be used by multiple packages at the same time. Setting +\cs{everypar} overwrites a prior usage. Even if one package is careful +and always uses +\begin{lstlisting} +\everypar=\expandafter{\the\everypar new tokens here} +\end{lstlisting} +so as not to stomp on another's usage, there's no guarantee that the +other package will not later set \lstinline!\everypar={}!. + +To get around this, the \textsf{\jobname} package takes control of the +six \cs{everyX} primitives listed above and for each one provides a +stack like interface for two additional token lists, one to be +expanded before the \cs{everyX} and one to be expanded after. For +example, +\begin{lstlisting} +\PushPreHook{hbox}{1} +\PushPreHook{hbox}{2} +\everyhbox={3} +\PushPostHook{hbox}{4} +\PushPostHook{hbox}{5} +\end{lstlisting} +will cause the insertion of the tokens |21345| at the start of an +\cs{hbox}. Note that \cs{PushPreHook} adds tokens to the \emph{left} +of the list of tokens to appear before those in \cs{everyhbox} whereas +\cs{PushPostHook} adds tokens to the \emph{right} of the list of +tokens to appear after those in \cs{everyhbox}. + +\section{Usage} +The \textsf{\jobname} package has no options and so should be loaded +using +\begin{lstlisting} +\usepackage{everyhook} +\end{lstlisting} +or +\begin{lstlisting} +\RequirePackage{everyhook} +\end{lstlisting} +as required. + +\subsection{Manipulating hooks} +There are 12 hooks, a pre and post hook for each of the six token +parameters |par|, |math|, |display|, |hbox|, |vbox|, and |cr|. The +first argument to all of the macros described in this section must be +one of these six. \textbf{All hook manipulation is \emph{global}.} + +\paragraph{Pre hooks.} +\DescribeMacro{\PushPreHook} +\DescribeMacro{\PopPreHook} +Additional tokens \meta{balanced text} are prepended to the pre hook +\meta{hook} using \cs{PushPreHook}\arg{\meta{hook}}\arg{\meta{balanced +text}}. The most recently pushed tokens can be popped off using +\cs{PopPreHook}\arg{\meta{hook}}. + +\paragraph{Post hooks.} +\DescribeMacro{\PushPostHook} +\DescribeMacro{\PopPostHook} +Additional tokens \meta{balanced text} are appended to the post hook +\meta{hook} using +\cs{PushPostHook}\arg{\meta{hook}}\arg{\meta{balanced text}}. The most +recently pushed tokens can be popped off using +\cs{PopPostHook}\arg{\meta{hook}}. + +\paragraph{Saving, restoring, and clearing hooks.} +\DescribeMacro{\SavePreHook} +\DescribeMacro{\SavePostHook} +\DescribeMacro{\RestorePreHook} +\DescribeMacro{\RestorePostHook} +\DescribeMacro{\ClearPreHook} +\DescribeMacro{\ClearPostHook} +Each of the 12 pre and post hooks can be saved to a macro, restored +from a macro, or cleared independently. To save the pre hook +\meta{hook} to the macro \cs{cs}, use +\cs{SavePreHook}\arg{\meta{hook}}\arg{\cs{cs}}. Restoring is +accomplished by \cs{RestorePreHook}\arg{\meta{hook}}\arg{\cs{cs}}. To +clear all of the tokens in a pre hook use +\cs{ClearPreHook}\arg{\meta{hook}}. The \cs{SavePostHook}, +\cs{RestorePostHook}, and \cs{ClearPostHook} are analogous. + +\section{Example} +As a nontrivial example of where this package can be used, consider +the following example. +\begin{lstlisting} +\documentclass{article} +\usepackage{everyhook} +\usepackage{lipsum} + +\begin{document} +\setlength{\parindent}{0pt} +\PushPreHook{par}{\llap{\textbullet\enskip}\null} +\paragraph{Lorem ipsum.} +\lipsum[1-4] +\PopPreHook{par} +\end{document} +\end{lstlisting} +This code will cause each paragraph of the \emph{lorem ipsum} text to +have no indentation and instead to place a bullet in the margin. See +Figure~\ref{fig:example}. If \cs{everypar} were used instead, the +\cs{paragraph} would replace the command to create the bullet with +those needed to typeset the paragraph title. + +\begin{figure}[p] +\centering +\fbox{\makebox[.975\textwidth][c]{\parbox{\dimexpr.975\textwidth-1in\relax}{ +\vspace*{\dimexpr .5in-3.25ex} +\PushPreHook{par}{\llap{\textbullet\enskip}\null} +\paragraph{Lorem ipsum.} +\lipsum[1-4] +\PopPreHook{par} + +\vskip.5in +}}} +\caption{Example output.} +\label{fig:example} +\end{figure} + +Note that this package is not a panacea. We had to add a \cs{null} to +the |par| hook because \cs{paragraph} uses \cs{lastbox} to remove the +indentation box. Without the \cs{null} it ends up removing the box +constructed by \cs{llap} instead. + +Using the post |par| hook solves the \cs{lastbox} problem, but then +the bullet is placed to the right of the \cs{paragraph} title. + +Perhaps a better way to solve this problem is to remove the +indentation box first, insert the bullet, and then place the box +after. In this way, the bullet is always to the left of the +paragraph indentation. +\begin{lstlisting} +\PushPreHook{par}{{\setbox0=\lastbox + \llap{\textbullet\enskip}\box0}} +\end{lstlisting} + +\section{Potential pitfalls} +As noted in the previous section, it can be tricky to use the |par| +hook correctly. This section contains an (almost certainly) incomplete +list of pitfalls to watch out for when using \textsf{\jobname}. +\begin{enumerate} +\item When using the |par| hooks, be aware that TeX will insert a box +with the width of \cs{parindent} before the tokens in the pre hook. +One way to handle this is to propogate the box to the right. +\item It is probably not a good idea to use the |hbox| and |vbox| +hooks at any place where TeX's output routine is likely to run. +\item \LaTeX's kernel takes control of the \cs{everymath} and +\cs{everydisplay} token parameters to make its own adjustments in much +the same way this package does. The \textsf{trace} package uses the +kernel's private macros to insert its own hooks. It is probably best +to only use the post |math| and |display| hooks to ensure that the +kernel has done what it needs to do before you start typesetting stuff +in math mode. +\item When using the |hbox| and |vbox| hooks, any hbox or vbox that +appears in a \cs{setbox} will have the \cs{afterassignment} token +inserted \emph{before} the hooks. This is no different from TeX's +normal behavior with \cs{afterassignment} and +\cs{everyhbox}/\cs{everyvbox}. +\item I'm sure there are others. +\end{enumerate} + +\DocInput{\jobname.dtx} +\Finale + +\typeout{**************************************************} +\typeout{*} +\typeout{* To finish the installation, you have to move the} +\typeout{* following file into a directory searched by TeX:} +\typeout{*} +\typeout{* \space\space \jobname.sty} +\typeout{*} +\typeout{* Documentation is in \jobname.\ifpdf pdf\else dvi\fi.} +\typeout{*} +\typeout{* Happy TeXing!} +\typeout{**************************************************} +\end{document} +% +% \fi +% +% \StopEventually{% +% \clearpage +% \phantomsection +% \addcontentsline{toc}{section}{Change History} +% \PrintChanges +% \phantomsection +% \addcontentsline{toc}{section}{Index} +% \PrintIndex +% } +% \clearpage +% \section{Implementation} +% The package begins with the usual package identification (not shown) +% and then it loads the \textsf{etoolbox} package. This is not +% strictly necessary, but it does simplify some stuff and provides +% handy macros for dealing with control sequence names. +% +% \changes{v1.0}{2010/09/26}{Initial version} +% \begin{macrocode} +\RequirePackage{etoolbox} +% \end{macrocode} +% +% \begin{macro}{\eh@definehook} +% This performs all of the setup work for each hook. First, it takes +% control of \TeX's token parameter given in the second argument. Then +% it shows the name of the primitive with a normal token register (and +% copies the current definition). The pre and post hooks are defined +% to be initially empty. +% \begin{macrocode} +\def\eh@definehook#1#2{% + \cslet{eh@every#1}#2% + \newtoks#2% + #2\csuse{eh@every#1}% + \csdef{eh@pre#1}{}% + \csdef{eh@post#1}{}% +% \end{macrocode} +% This is slightly tricky to get right. Basically, we want to set the +% \cs{everyfoo} primitive which we have saved as \cs{eh@everyfoo} +% like +% +% \indent\lstinline!\eh@everyfoo={\eh@prefoo\the\expandafter\everyfoo\eh@postfoo}!. +% +% The reason for the \cs{expandafter} is to make sure it is expanded +% before the the token register \cs{everyfoo} is expanded. Thus if the +% post hook is empty, then code in \cs{everyfoo} sees no additional +% tokens, in case that is important. +% \begin{macrocode} + \csuse{eh@every#1}\expandafter{\csname eh@pre#1\expandafter\endcsname + \expandafter\the\expandafter\expandafter\expandafter#2% + \csname eh@post#1\endcsname}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\everypar} +% Define the hooks for the |par| hook. +% \begin{macrocode} +\eh@definehook{par}\everypar +% \end{macrocode} +% \end{macro} +% \begin{macro}{\frozen@everymath} +% \begin{macro}{\frozen@everydisplay} +% Define the |math| and |display| hooks. Since the \LaTeX\ kernel has +% already saved \cs{everymath} and \cs{everydisplay} into the frozen +% macros, we take control by redefining the frozen ones instead. +% \begin{macrocode} +\eh@definehook{math}\frozen@everymath +\eh@definehook{display}\frozen@everydisplay +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\everyhbox} +% \begin{macro}{\everyvbox} +% \begin{macro}{\everycr} +% Define the |hbox|, |vbox|, and |cr| hooks and free up some used +% memory. +% \begin{macrocode} +\eh@definehook{hbox}\everyhbox +\eh@definehook{vbox}\everyvbox +\eh@definehook{cr}\everycr +\undef\eh@definehook +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\eh@hookseparator} +% An separator used to separate tokens in each hook. +% \begin{macrocode} +\def\eh@hookseparator{} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\eh@checkhook} +% Check that the hook is one of the six. +% \begin{macrocode} +\def\eh@checkhook#1#2{% + \ifcsdef{eh@every#1}{}{\PackageError{everyhook}{Argument #1 to + \protect#2\space is invalid}{There is no hook for + \protect\every#1.}}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\eh@checkhooknotempty} +% Check that the hook is both defined and not empty so that we can +% pop. +% \begin{macrocode} +\def\eh@checkhooknotempty#1#2#3{% + \eh@checkhook{#2}#3% + \ifcsempty{eh@#1#2}{\PackageError{everyhook}{The #1 hook for + \protect\every#2\space is empty}{I have seen too many + \protect#3{#2}s.}{}}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PushPreHook} +% Prepend tokens to the pre hook, separated via the separator. +% \begin{macrocode} +\newrobustcmd\PushPreHook[2]{% + \eh@checkhook{#1}\PushPreHook + \def\eh@tempi{#2}% + \letcs\eh@tempii{eh@pre#1}% + \expandafter\gdef\csname eh@pre#1\expandafter\expandafter + \expandafter\endcsname\expandafter\expandafter + \expandafter{\expandafter\eh@tempi\expandafter + \eh@hookseparator\eh@tempii}% + \undef\eh@tempi + \undef\eh@tempii +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PopPreHook} +% \begin{macro}{\eh@popprehook} +% Check that the hook is not empty, and then pop off the left tokens +% and separator. We can use delimited parameters to strip off the +% first set of tokens. +% \begin{macrocode} +\newrobustcmd\PopPreHook[1]{% + \eh@checkhooknotempty{pre}{#1}\PopPreHook + \expandafter\eh@popprehook\csname eh@pre#1\expandafter + \expandafter\expandafter\endcsname + \csname eh@pre#1\endcsname\eh@hookend +} +\def\eh@popprehook#1#2\eh@hookseparator#3\eh@hookend{\gdef#1{#3}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\PushPostHook} +% Append a separator and tokens to the post hook. +% \begin{macrocode} +\newrobustcmd\PushPostHook[2]{% + \eh@checkhook{#1}\PushPostHook + \letcs\eh@tempi{eh@post#1}% + \expandafter\gdef\csname eh@post#1\expandafter\endcsname + \expandafter{\eh@tempi\eh@hookseparator#2}% + \undef\eh@tempi +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PopPostHook} +% \begin{macro}{\eh@popposthook} +% \begin{macro}{\eh@sentinel} +% Check that the post hook is not empty. Then, iterate over the tokens +% in the list until we reach the end and strip that off. +% \begin{macrocode} +\newrobustcmd\PopPostHook[1]{% + \eh@checkhooknotempty{post}{#1}\PopPostHook + \letcs\eh@tempi{eh@post#1}% + \expandafter\eh@popposthook\csname eh@post#1\expandafter + \endcsname\expandafter{\expandafter}\eh@tempi + \eh@hookend\eh@hookseparator\eh@sentinel\eh@hookend + \undef\eh@tempi +} +\def\eh@popposthook#1#2\eh@hookseparator#3\eh@hookseparator#4\eh@hookend{% + \def\eh@tempi{#4}% + \ifdefequal\eh@sentinel\eh@tempi% + {\gdef#1{#2}\undef\eh@tempi}% + {\eh@popposthook#1{#2\eh@hookseparator#3}\eh@hookseparator#4\eh@hookend}% +} +\def\eh@sentinel{\eh@sentinel} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\ClearPreHook} +% \begin{macro}{\ClearPostHook} +% Reset the pre/post hook to empty. +% \begin{macrocode} +\newrobustcmd\ClearPreHook[1]{% + \eh@checkhook{#1}\ClearPreHook + \global\csdef{eh@pre#1}{}% +} +\newrobustcmd\ClearPostHook[1]{% + \eh@checkhook{#1}\ClearPostHook + \global\csdef{eh@post#1}{}% +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\SavePreHook} +% \begin{macro}{\SavePostHook} +% \begin{macro}{\RestorePreHook} +% \begin{macro}{\RestorePostHook} +% \cs{let} the hook to the supplied control sequence to save. Perform +% the \cs{let} in the other direction to restore. +% \begin{macrocode} +\newrobustcmd\SavePreHook[2]{% + \eh@checkhook{#1}\SavePreHook + \letcs#2{eh@pre#1}% +} +\newrobustcmd\SavePostHook[2]{% + \eh@checkhook{#1}\SavePostHook + \letcs#2{eh@post#1}% +} +\newrobustcmd\RestorePreHook[2]{% + \eh@checkhook{#1}\RestorePreHook + \global\cslet{eh@pre#1}#2% +} +\newrobustcmd\RestorePostHook[2]{% + \eh@checkhook{#1}\RestorePostHook + \global\cslet{eh@post#1}#2% +} +\endinput +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +\endinput -- cgit v1.2.3