% \iffalse % %<*internal> \begingroup % %<*batchfile> \input docstrip.tex \keepsilent \preamble ____________________________ The HARDWRAP package (C) 2010-2011 Will Robertson (C) 2010 Kevin Godby License information appended \endpreamble \postamble Copyright (C) 2010 by Will Robertson Copyright (C) 2010 by Kevin Godby Distributable under the LaTeX Project Public License, version 1.3c or higher (your choice). The latest version of this license is at: http://www.latex-project.org/lppl.txt This work is "maintained" (as per LPPL maintenance status) by Will Robertson. This work consists of the file hardwrap.dtx and the derived files hardwrap.sty, hardwrap.ins, and hardwrap.pdf. \endpostamble \askforoverwritefalse \generate{\file{hardwrap.sty}{\from{hardwrap.dtx}{package}}} % %\endbatchfile %<*internal> \generate{\file{hardwrap.ins}{\from{hardwrap.dtx}{batchfile}}} \generate{\file{hardwrap.tests}{\from{hardwrap.dtx}{tests}}} \generate{\file{hardwrap-test.tex}{\from{hardwrap.dtx}{testsuite,tests}}} \def\tmpa{plain} \ifx\tmpa\fmtname\endgroup\expandafter\bye\fi \endgroup % % % \begin{macrocode} %<*driver> \ProvidesFile{hardwrap.dtx} % %\ProvidesPackage{hardwrap} %<*package> [2011/02/12 v0.2 Hard wrap messages] % % \end{macrocode} % %<*driver> \documentclass{ltxdoc} \makeatletter \renewcommand\meta@font@select{\rmfamily\itshape} \usepackage[osf,sc]{mathpazo} \usepackage{inconsolata} \usepackage[scaled=0.83]{berasans} \usepackage[T1]{fontenc} \usepackage{textcomp} \usepackage[final]{microtype} \linespread{1.1} \frenchspacing \usepackage{geometry} \geometry{b5paper} \usepackage{qstest,hologo} %%%%% % See http://groups.google.com.au/group/comp.text.tex/msg/7588fd83dd9ce0ea \usepackage{calc,framed} \expandafter\newif\csname ifcontframe\endcsname \newcommand*{\Fr@meSetup}{% \global\contframefalse \def\FrameCommand##1{% \vbox{\FrameTitle{\Fr@meCurrent}\hbox{##1}} \global\let\Fr@meCurrent\Fr@meNext \ifcontframe \global\let\Fr@meNext \macrotitlecont \fi \global\contframetrue}% \global\let\Fr@meCurrent\macrotitle \global\let\Fr@meNext\macrotitle} \newcommand*{\FrameTitle}[1]{% \nobreak \vskip -0.7\FrameSep \rlap{\frametitle{#1}}\nobreak\nointerlineskip \vskip 0.7\FrameSep} \newcommand*{\frametitle}[1]{% \parbox{\linewidth}{\footnotesize\strut#1}% }% \newenvironment{macroframe}{% \Fr@meSetup \MakeFramed{% \advance\hsize-\width \FrameRestore}}% {\global\contframefalse \endMakeFramed } \def\macrotitlecont{\macrotitleshort\space(\textit{cont.})} \protected\def\framelabel#1{\texttt{\color{niceblue}#1}} \def\macrotitle{} \renewenvironment{macro}[1]{% \@for\@ii:={{},#1}\do{% \ifx\macrotitle\@empty \let\macrotitle\@nil \else\ifx\macrotitle\@nil \edef\macrotitle{\framelabel{\detokenize\expandafter{\@ii}\unskip}}% \edef\macrotitleone{\framelabel{\detokenize\expandafter{\@ii}\unskip}}% \let \macrotitleshort \macrotitleone \else \edef\macrotitle{\macrotitle, \framelabel{\detokenize\expandafter{\@ii}\unskip}}% \edef\macrotitleshort{\macrotitleone, etc.}% \fi\fi } \begin{macroframe} \noindent\ignorespaces }{% \end{macroframe} } \usepackage{titlesec} \titleformat{\part}{\Large}{Part \thepart}{1em}{\scshape} \titleformat{\section}{\smallskip\color{niceblue}}{\S\thesection}{1em}{} \renewcommand\contentsname{} \usepackage{tocloft,varwidth} \setcounter{tocdepth}{1} \def\tocwidthA{0.45} \def\tocwidthB{0.5} \renewcommand\cftpartfont{\scshape} \renewcommand\cftsecfont{\small} \renewcommand\cftsecpagefont{\small} \renewcommand\cftpartpagefont{\normalsize} \setlength\cftbeforepartskip{4pt} \setlength\cftbeforesecskip{0pt} \renewcommand\cftpartleader{} \renewcommand\cftsecleader{} \renewcommand\cftpartafterpnum{\cftparfillskip} \renewcommand\cftsecafterpnum{\cftparfillskip} \renewcommand\@cftmaketoctitle{\bigskip} \newcommand\pretoc{{% \addtocontents{toc}{% \protect\noindent\protect\begin{varwidth}[t]{\tocwidthA\linewidth}% }% }} \newcommand\splittoc{% {\addtocontents{toc}{\protect\end{varwidth}\protect\hfill}}% {\addtocontents{toc}{\protect\begin{varwidth}[t]{\protect\tocwidthB\protect\linewidth}}}% } \newcommand\posttoc{{\addtocontents{toc}{\protect\end{varwidth}\protect\par}}} \usepackage{xcolor,hardwrap,lipsum,booktabs,fancyvrb,hypdoc} \fvset{gobble=2} \hypersetup{% linktocpage, linkcolor=niceblue, anchorcolor=niceblue, urlcolor=niceblue, pdfauthor={Will Robertson and Kevin Godby} } % A few shorthand macros to ensure consistency \newcommand{\email}[1]{$\langle$\href{mailto:#1}{#1}$\rangle$} \usepackage{xspace} \newcommand{\hairsp}{\kern1pt}% hair space \let\latintext\relax% or \emph for italics \newcommand*{\latinphrase}[1]{\latintext{#1}\@ifnextchar.{}{.\xspace}} \newcommand*{\ie}{\latinphrase{i.\hairsp e\@}}% TODO search for and add comma if not found \newcommand*{\eg}{\latinphrase{e.\hairsp g\@}}% TODO search for and add comma if not found \newcommand*{\etc}{\latinphrase{etc}} \newcommand*{\etal}{\latinphrase{et\,al}} \newcommand*{\secref}[1]{\hyperref[#1]{section~}\ref{#1}} % Hang the code line numbers in the margin \def\macro@code{% \topsep \MacrocodeTopsep \@beginparpenalty \predisplaypenalty \if@inlabel\leavevmode\fi \trivlist \parskip \z@ \item[]% \macro@font \leftskip\@totalleftmargin% \advance\leftskip-\MacroIndent \rightskip\z@ \parindent\z@ \parfillskip\@flushglue \blank@linefalse \def\par{\ifblank@line \leavevmode\fi \blank@linetrue\@@par \penalty\interlinepenalty} \obeylines \let\do\do@noligs \verbatim@nolig@list \let\do\@makeother \dospecials \global\@newlistfalse \global\@minipagefalse \ifcodeline@index \everypar{\global\advance\c@CodelineNo\@ne \llap{\theCodelineNo\ \hskip\@totalleftmargin}% \check@module}% \else \everypar{\check@module}% \fi \init@crossref} \definecolor{niceblue}{rgb}{0.1,0.3,0.9} \def\theCodelineNo{\textcolor{niceblue}{\sffamily\tiny\arabic{CodelineNo}}} \newcommand*\pkg[1]{\textsf{#1}} \newcommand*{\earg}[1]{{\ttfamily\char`\{}\texttt{#1}{\ttfamily\char`\}}} \begin{document} \DocInput{\jobname.dtx} \end{document} % % % \fi % % \errorcontextlines=999 % \makeatletter % % \GetFileInfo{\jobname.dtx} % % \title{The \pkg{\jobname} package} % \author{Will Robertson\\ \normalsize\email{will.robertson@latex-project.org} \and Kevin Godby\\\normalsize \email{kevin@godby.org}} % \date{\filedate \qquad \fileversion} % % \maketitle % % \begin{abstract} % \noindent This package provides facilities for hard-wrapping text to a certain % number of characters per line. % The primary purpose is to make it easier for package authors to write % readable informational messages to the console and log file; % wrappers around \cs{PackageWarning} \etal\ are provided for this. % \end{abstract} % % \tableofcontents % \bigskip % % \pretoc % \part{User documentation} % \section{Introduction} % % The \pkg{\jobname} package provides a macro for word-wrapping text to a % certain number of characters per line. In % addition, helper macros are available for package and document class authors % to use in automatically wrapping informational, warning, and error messages. % This package requires \hologo{eTeX}. % % \section{Wrapping text} % % The main function provided by this package is the \cs{HardWrap} command, % which takes five arguments. % \begin{quote} % \cs{HardWrap} \marg{function} \marg{width} \marg{setup code} \marg{newline} \marg{text} % \end{quote} % This command will wrap \meta{text} to a text block of \meta{width} characters % wide, inserting \meta{newline} at the end of each line and processing the % result with \meta{function}. The \meta{text} is fully expanded before being % hard-wrapped; while doing so, the \meta{setup code} may be used to change % local command definitions. % % Inside \meta{text}, you may use \verb|\\| to force a new line and \verb*|\ | to % insert a space. % A literal \verb|^^J| will also be treated as a forced \meta{newline}. % % Examples will be given in \secref{sec:examples}. % % \section{Wrapping log messages} % % A common use case for the \cs{HardWrap} macro is to format the % informational, warning, and error messages that are printed to the terminal % and log file. In support of this, we've provided a simple interface for % package and document class authors to do this. % % \begin{quote} % \cs{GenerateLogMacros}\earg{package}\oarg{prefix}\marg{package name}\\ % \cs{GenerateLogMacros}\earg{class}\texttt{\space \space}\oarg{prefix}\marg{class name} % \end{quote} % If the optional argument \meta{prefix} is not given, it is set equal to \meta{package name}. % These two commands will generate the following macros: % % \begin{quote} % \cs{\meta{prefix}@info}\marg{info}\\ % \cs{\meta{prefix}@info@noline}\marg{info}\\ % \cs{\meta{prefix}@warning}\marg{warning}\\ % \cs{\meta{prefix}@warning@noline}\marg{warning}\\ % \cs{\meta{prefix}@error}\marg{error}\marg{help} % \end{quote} % % For instance, calling \cs{GenerateLogMacros}\earg{package}\earg{mypackage} % will create macros called \cs{mypackage@info}, \cs{mypackage@warning}, \etc, % which internally use \cs{PackageInfo}, \cs{PackageWarning}, and so on, to % handle their respective messages. % The arguments for the generated macros are the same as the arguments for % \cs{PackageInfo}\marg{package name}, \cs{PackageWarning}\marg{package name}, \etc. Additionally, info messages may be printed with % \cs{\meta{prefix}@info@noline} in which \LaTeX's % `\texttt{on input line \meta{num}}' suffix is suppressed. % % The \cs{GenerateLogMacros}\earg{class} command instead generates analogous % macros using \cs{ClassInfo}\marg{\rmfamily class name}, % \cs{ClassWarning}\marg{\rmfamily class name}, \etc. % % Note that no punctuation is added after messages, unlike standard \LaTeX. % You are free to punctuate your messages as you wish. % % As with the \cs{HardWrap} command, % \verb*|\ | and \verb|\\| are defined locally inside these messages to % mean, respectively, \meta{space} and \meta{newline}. % % Additional redefinitions are stored in the macro \cs{HardWrapSetup}, which may % be altered before executing \cs{GenerateLogMacro} to change the behaviour % of the generated commands. By default, \cs{HardWrapSetup} is defined as % \begin{Verbatim} % \def\HardWrapSetup{% % \def\MessageBreak{\\}% % \def\newline{\\}% % \def\emph##1{\string_##1\string_}% % \def\textit##1{/##1/}% % \def\textbf##1{*##1*}% % } % \end{Verbatim} % The redefinitions for \cs{emph}, \cs{textit}, and \cs{textbf} are examples % of the type of customisation you might like to perform. % % \section{Changing the line lengths} % % While \pkg{\jobname} attempts to determine the maximum line % lengths based on where \TeX\ will wrap its console and log output, % you may wish to override the value found using % \cs{setmaxprintline}\marg{value}. % This macro takes an integer value which is subsequently used by the % commands generated with \cs{GenerateLogMacros} as the % maximum line width allowed in the terminal output and log file. By default % this value is~\texttt{79}. % % \section{Examples} % \label{sec:examples} % % The command % \begin{Verbatim} % \HardWrap{\PackageWarning{foobar}}{50}{\HardWrapSetup}{\MessageBreak}{% % Sed feugiat. Cum sociis natoque...;} % \end{Verbatim} % produces the following in the console output: % \begin{Verbatim}[fontsize=\footnotesize] % Package foobar Warning: Sed feugiat. Cum sociis natoque penatibus et magnis % (foobar) dis parturient montes, nascetur ridiculus mus. Ut % (foobar) pellentesque augue sed urna. Vestibulum diam eros, % (foobar) fringilla et, consectetuer eu, nonummy id, sapien. % (foobar) Nullam at lectus. In sagittis ultrices mauris. % (foobar) Curabitur malesuada erat sit amet massa. Fusce % (foobar) blandit. Aliquam erat volutpat. Aliquam euismod. % (foobar) Aenean vel lectus. Nunc imperdiet justo nec % (foobar) dolor; on input line 102. % \end{Verbatim} % Compare this to the following without the manual wrapping; \TeX\ breaks % lines at 79 characters without keeping words together (\eg, `Vestibulum' % broken between lines two and three): % \begin{Verbatim}[fontsize=\footnotesize] % Package foobar Warning: Sed feugiat. Cum sociis natoque penatibus et magnis dis % parturient montes, nascetur ridiculus mus. Ut pellentesque augue sed urna. Ves % tibulum diam eros, fringilla et, consectetuer eu, nonummy id, sapien. Nullam at % lectus. In sagittis ultrices mauris. Curabitur malesuada erat sit amet massa. % Fusce blandit. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. Nunc % imperdiet justo nec dolor; on input line 110. % \end{Verbatim} % % The \cs{HardWrap} macro can also be useful when writing to an external file. % For example, one may use: % \begin{Verbatim} % \newwrite\textfile % \immediate\openout\textfile=\jobname.txt\relax % \HardWrap{\immediate\write\textfile}{50}{\HardWrapSetup}{^^J}{% % Sed feugiat. Cum sociis natoque...;} % \closeout\textfile % \end{Verbatim} % to write the text to a file after being hard-wrapped with carriage returns (\verb|^^J|) after each line. % % \section{Support} % % Development and historical versions are available from GitHub at % \url{http://github.com/wspr/hardwrap/}. % % Please report bugs and feature suggestions to the issue tracker at % \url{http://github.com/wspr/hardwrap/issues}. % % \clearpage % \splittoc % \part{Implementation} % % Read on if you're curious what's behind the curtain. % % \begin{macrocode} %<*package> % \end{macrocode} % % \section{Preliminaries} % \begin{macrocode} \IfFileExists{ifplatform.sty}{% \RequirePackage{ifplatform} }{% \newif\ifwindows \IfFileExists{/dev/null}{\windowsfalse}{\windowstrue} } % \end{macrocode} % % \begin{macrocode} \IfFileExists{pdftexcmds.sty}{% \RequirePackage{pdftexcmds} }{% \def\pdf@shellescape{\pdfshellescape} } % \end{macrocode} % % \begin{macrocode} \RequirePackage{ifxetex} % \end{macrocode} % % \begin{macro}{\hw@charcount,\hw@wordcount} % These counters hold, respectively, the number of characters on the current % line and the number of characters in the current word. % \begin{macrocode} \newcount\hw@charcount \newcount\hw@wordcount % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@currtext,\hw@currline,\hw@currword} % The following are local variables to store the current contents of the wrapped text, line, and word. % \begin{macrocode} \def\hw@currtext{} \def\hw@currline{} \def\hw@currword{} % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@protected@newline} % This macro is called each time a line break is created. It typically holds % \cs{MessageBreak} for log messages, but could be set to \cs{\char`\\} for typeset % text. % \begin{macrocode} \protected\def\hw@protected@newline{} % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@protected@space,\hw@expanding@space} % The \cmd\hw@protected@space\ definition of `space' is designed to be switched for a real space later on using \cmd \hw@expanding@space, which is also inserted into scratch variables as the `real' space char. % \begin{macrocode} \protected\def\hw@protected@space{ } \let\hw@expanding@space\space % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@insert@newline} % This is a placeholder to show where manual newlines are inserted. % (It will never be executed.) % \begin{macrocode} \protected\def\hw@insert@newline{\hw@insert@newline} % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@scanstop} % This is a `quark' from expl3 designed to delimit scanning; it will never be executed, else an infinite loop results. % \begin{macrocode} \protected\def\hw@scanstop{\hw@scanstop} % \end{macrocode} % \end{macro} % % \section{Utility macros} % % \begin{macro}{\hw@strlen,\hw@strlen@of} % A simple string-length macro. % \cs{hw@strlen}\marg{token list} is the number of tokens (or brace groups) of its \meta{token list} argument without expansion. % \begin{macrocode} \def\hw@strlen#1{% \numexpr0\hw@Ncharscan#1\hw@scanstop\relax } \def\hw@Ncharscan#1{% \ifx#1\hw@scanstop \expandafter\@gobble \else \expandafter\@firstofone \fi {+1\hw@Ncharscan}% } % \end{macrocode} % Variant \cs{hw@strlen@of}\meta{macro} is the number of tokens (or brace groups) of the contents of its \meta{macro} argument. % \begin{macrocode} \def\hw@strlen@of#1{% \expandafter\hw@strlen\expandafter{#1}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@maxprintline} % Some code to detect \TeX's \textit{max\_print\_line} value. % This only works for \hologo{pdfTeX} in \TeX{} Live. % \begin{macrocode} \newcount\hw@maxprintline \ifluatex\else \ifxetex\else \ifwindows\else \ifnum\pdf@shellescape>0\relax \hw@maxprintline=\@@input"|kpsewhich -var-value=max_print_line"\relax \fi \fi \fi \fi % \end{macrocode} % In the non-unlikely chance the correct value cannot be determined, the usual default is assumed. This value will rarely, if ever, be different to the default, so assuming this number is very safe. % \begin{macrocode} \ifnum\hw@maxprintline=0\relax \hw@maxprintline=79\relax % default \fi % \end{macrocode} % \end{macro} % % \begin{macro}{\setmaxprintline} % In case the code above borks the \cs{hw@maxprintline} value, the user can set it manually with the \cs{setmaxprintline} macro. % \begin{macrocode} \newcommand*{\setmaxprintline}[1]{% \hw@maxprintline=#1\relax } % \end{macrocode} % \end{macro} % % % \section{Main procedure} % % The idea for hard-wrapping the text is to assume we can fully expand the % argument and then iterate character-by-character over the message inserting % \meta{newline} commands where appropriate. The steps are: % \begin{enumerate} % \item Make local redefinitions for general commands, including special % placeholders for \meta{space} and \meta{newline}. % \item Fully expand the text-to-be-wrapped with appropriate definitions of % \cs{protect} and \cs{noexpand} so the resultant text can be assumed to % completely `safe' to scan over (and continue expanding) but \emph{without} % removing important macro placeholders for \meta{space} and \meta{newline}. % \item Then scan character by character. Whenever a space is found, check the % last word length and either append the word to the current line if it will % fit, or start a new line with a forced line break represented by another % special placeholder macro. Spaces are represented with placeholders so % multiple spaces don't collapse according to \TeX's usual space-handling % rules. % \item Finally process the wrapped text with appropriate meanings for the % placeholder macros. % \end{enumerate} % % \begin{macro}{\HardWrap} % Here's the main command that implements the steps outlined above. % Arguments: % \begin{enumerate}\parskip=0pt\itemsep=0pt % \item \marg{function} % \item \marg{chars to wrap to} % \item \marg{setup} % \item \marg{newline} % \item \marg{text} % \end{enumerate} % This is the macro that does everything. % Note that the \cs{space} is first made `protected' and then restored again. % \begin{macrocode} \newcommand*\HardWrap[5]{% \begingroup \hw@maxprintline=\numexpr#2\relax % \end{macrocode} % Replacements for user commands: % \begin{macrocode} \let\space\hw@protected@space \def\ {\space}% \let\\\hw@insert@newline % \end{macrocode} % To avoid problems with repeated edef with arbitrary csnames: % \begin{macrocode} \let\noexpand\string % \end{macrocode} % Execute the custom setup, and then fully expand the text % to be wrapped, turning \cs{protect}ed macros into strings. % (Fully \cs{protected} macros will still be actual control sequences % at this point.) % \begin{macrocode} \begingroup #3% \let\protect\string \xdef\@tempa{#5}% \endgroup % \end{macrocode} % Now scan over the text token by token, transforming it into an % intermediate representation of fully wrapped text. % Then fully expand this intermediate form into its final form, % ready to be processed by the input function \verb|#1|. % \begin{macrocode} \expandafter\hw@scan\@tempa\hw@scanstop \def\\{\hw@protected@newline}% \def\hw@protected@newline{#4}% \let\space\hw@expanding@space \@temptokena={#1}% \expandafter\the\expandafter\@temptokena\expandafter{\hw@wrappedtext}% \endgroup } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@scan} % Convenience wrapper for \cs{futurelet}. % \begin{macrocode} \def\hw@scan{% \futurelet\let@token\hw@process } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@process} % The \cs{hw@process} macro contains the actual word-wrapping algorithm. % The text is scanned token by token. Each token falls into one of five % categories: (1)~the stop token \cs{hw@scanstop}, (2)~a space token, % (3)~a newline insertion, (4)~an opening brace, or (5)~anything else. % % \begin{enumerate} % \item % If we encounter the \cs{hw@scanstop} token, then we've hit the end of the % string. Swallow the stop token and stop processing. % \item % If we find a space, add the word to the current line if it fits, otherwise % insert a line break and put the word on its own line. Continue reading tokens. % \item % If we find an explicit `newline', we process it much as if it were a space and % the current word is the last one that can fit on the line. % To continue, skip the actual token that is the `newline' and then start scanning again. % \item % If we find an opening brace \verb|{|, we read in the entire brace group, and then % re-insert it in the scanner surrounded with brace-strings. I.e., braces are printed % in the output. % \item % If the token doesn't fall into one of the above special cases, we'll just append it to % the current word and continue reading tokens. % \end{enumerate} % \begin{macrocode} \def\hw@process{% \ifx\let@token\hw@scanstop\relax \hw@process@end \let\next\@gobble \else\ifx\let@token\@sptoken \hw@process@space \def\next{\afterassignment\hw@scan\let\@tempa= }% \else\ifx\let@token\hw@insert@newline \hw@process@messagebreak \def\next{\expandafter\hw@scan\@gobble}% \else\ifx\let@token^^J \hw@process@messagebreak \def\next{\expandafter\hw@scan\@gobble}% \else\ifx\let@token\bgroup \def\next{\expandafter\hw@dochar\hw@process@group}% \else \let\next\hw@dochar \fi\fi\fi\fi\fi \next } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@dochar} % After a letter, the \cs{hw@dochar} macro just appends a token (non-space and non-stop token) to the current word. % \begin{macrocode} \def\hw@dochar#1{% \edef\hw@currword{\hw@currword #1}% \hw@scan } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@process@space} % \begin{macrocode} \def\hw@process@space{% \hw@wordcount=\hw@strlen@of\hw@currword\relax \ifnum\numexpr(\hw@charcount+\hw@wordcount)\relax<\hw@maxprintline \advance\hw@charcount by \hw@wordcount \ifx\hw@currline\@empty \edef\hw@currline{\hw@currword}% \else \advance\hw@charcount by 1\relax % account for the space character \edef\hw@currline{\hw@currline\hw@expanding@space\hw@currword}% \fi \else \hw@charcount=\hw@wordcount\relax \edef\hw@currtext{\hw@currtext\hw@currline\hw@protected@newline}% \let\hw@currline\hw@currword \fi \let\hw@currword\@empty } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@process@messagebreak} % \begin{macrocode} \def\hw@process@messagebreak{% \hw@wordcount=\hw@strlen@of\hw@currword\relax \ifnum\numexpr(\hw@charcount+\hw@wordcount)<\hw@maxprintline \edef\hw@currtext{% \hw@currtext \ifx\hw@currline\@empty\else \hw@currline\space \fi \hw@currword\hw@protected@newline }% \hw@charcount=0\relax \let\hw@currline\@empty \else \edef\hw@currtext{\hw@currtext\hw@currline\hw@protected@newline}% \hw@charcount=\hw@wordcount \let\hw@currline\hw@currword \fi \let\hw@currword\@empty } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@process@end} % The final stage of processing the text. We've just come to the end of the final % word on the final line: add the word to the current line if it fits, otherwise insert a line % break and put the word on its own line. % \begin{macrocode} \def\hw@process@end{% \hw@wordcount=\hw@strlen@of\hw@currword\relax \ifnum\numexpr(\hw@charcount+\hw@wordcount)<\hw@maxprintline \edef\hw@wrappedtext{% \hw@currtext \ifx\hw@currline\@empty\else \hw@currline\space \fi \hw@currword }% \else \edef\hw@wrappedtext{% \hw@currtext\hw@currline\hw@protected@newline\hw@currword }% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@process@group} % If a brace group is found, we read it as an argument and then surround it with brace strings % (\ie, braces are printed). % \begin{macrocode} \edef\hw@process@group#1{% \expandafter\@gobble\string\{% #1% \expandafter\@gobble\string\}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\HardWrapSetup} % This is the command to use if you want to `special-case' some meanings to be more appropriate inside message text. When using \cs{GenerateLogMacros}, it is used by default for argument \verb|#3| in \cs{HardWrap}. % \begin{macrocode} \def\HardWrapSetup{% \def\MessageBreak{\\}% \def\newline{\\}% \def\emph##1{\string_##1\string_}% \def\textit##1{/##1/}% \def\textbf##1{*##1*}% } % \end{macrocode} % \end{macro} % % \section{Wrapping log messages} % % \begin{samepage} % \LaTeX{} informational, warning, and error messages are printed in the % format: % \begin{center} % \ttfamily\small % \begin{tabular}{l@{\space}l} % Package \meta{pkgname} Info: & This is an informational message.\\ % (\meta{pkgname}) & That spans multiple lines. The\\ % (\meta{pkgname}) & \string\MessageBreak\space macro is used to split\\ % (\meta{pkgname}) & the text across lines.\\ % \leftarrowfill$A$\rightarrowfill & \leftarrowfill$B$\rightarrowfill\\ % \multicolumn{2}{c}{\leftarrowfill$\textrm{\textit{max\_print\_line}}$\rightarrowfill} % \end{tabular} % \end{center} % \end{samepage} % The maximum line length ($\textit{max\_print\_line}$) is used by % \TeX{} for all log file and terminal output. It defaults to 79 characters % but may be changed by editing the \texttt{texmf.cnf} file. % % The length of $A$ is the sum of three values: % \begin{enumerate} % \item whether it's a class or package message: add 6 for class messages, % and 8 for package messages; % \item the length of the package name; % \item the type of message: information (add 7), warning (add 10), or error % (add~10). % \end{enumerate} % The length of $B$ is the difference between $\textit{max\_print\_line}$ and % $A$ plus one for the extra space between them. % Note that the length of $B$ for the warning and error text is the same. % % \begin{macro}{\hw@suffix} % This string is used as a suffix to \LaTeX\ warnings and info messages % to push the automatic `on input line \meta{num}' onto the next line. % This makes writing grammatically correct messages somewhat easier. % \begin{macrocode} \newcommand\hw@suffix{^^JThis message occurred} % \end{macrocode} % \end{macro} % % \begin{macro}{\GenerateLogMacros} % Shortcuts are provided for generating logging macros that automatically wrap % the text provided to them. The \cs{GeneratePackageLogMacros} and % \cs{GenerateClassLogMacros} calculate the various lengths of $B$ % appropriately. % \begin{macrocode} \newcommand\GenerateLogMacros[1]{% \lowercase{\def\hw@tempa{#1}}% \def\hw@tempb{package}% \ifx\hw@tempa\hw@tempb \expandafter\GeneratePackageLogMacros \else \def\hw@tempb{class}% \ifx\hw@tempa\hw@tempb \expandafter\expandafter\expandafter\GenerateClassLogMacros \else \PackageError{hardwrap}{\MessageBreak \string\GenerateLogMacros\space only accepts "package" \MessageBreak or "class" types% }{% E.g., \detokenize{\GenerateLogMacros{package}[HW]{hardwrap}}% }% \fi \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\GeneratePackageLogMacros,\GenerateClassLogMacros} % \begin{macrocode} \newcommand{\GeneratePackageLogMacros}[2][]{% \hw@generate@logging@macros{package}{#1}{#2}% {\hw@maxprintline-\hw@strlen{#2}-16}% info length {\hw@maxprintline-\hw@strlen{#2}-19}% warning length } % \end{macrocode} % % \begin{macrocode} \newcommand{\GenerateClassLogMacros}[2][]{% \hw@generate@logging@macros{class}{#1}{#2}% {\hw@maxprintline-\hw@strlen{#2}-14}% info length {\hw@maxprintline-\hw@strlen{#2}-17}% warning length } % \end{macrocode} % \end{macro} % % \begin{macro}{\hw@generate@logging@macros} % And now for the code that generates all the logging macros. Arguments: % \begin{enumerate}\itemsep=0pt\parskip=0pt\parsep=0pt % \item \marg{`package' or `class'} % \item \marg{prefix} % \item \marg{package name} % \item \marg{info message length} % \item \marg{warning message length} % \end{enumerate} % The \meta{info\dots} and \meta{warning message length} values correspond to % the calculation of $B$ as described above. % % First of all, if the \meta{prefix} is not specified then fall back to the \meta{package name}: % \begin{macrocode} \newcommand{\hw@generate@logging@macros}[5]{% \def\@tempa{#2}\ifx\@tempa\@empty \hw@generate@logging@macros@aux{#1}{#3}{#3}{#4}{#5}% \else \hw@generate@logging@macros@aux{#1}{#2}{#3}{#4}{#5}% \fi } % \end{macrocode} % Finally, the main procedure. Info messages first: % \begin{macrocode} \newcommand{\hw@generate@logging@macros@aux}[5]{% \expandafter\edef\csname #2@info\endcsname##1{% \noexpand\HardWrap {\@nameuse{hw@#1@info}{#3}} {\number\numexpr#4\relax} {\unexpanded\expandafter{\HardWrapSetup}} {\noexpand\MessageBreak} {##1}% }% \expandafter\edef\csname #2@info@noline\endcsname##1{% \noexpand\HardWrap {\@nameuse{hw@#1@info@noline}{#3}} {\number\numexpr#4\relax} {\unexpanded\expandafter{\HardWrapSetup}} {\noexpand\MessageBreak} {##1}% }% % \end{macrocode} % Now warnings: % \begin{macrocode} \expandafter\edef\csname #2@warning\endcsname##1{% \noexpand\HardWrap {\@nameuse{hw@#1@warning}{#3}} {\number\numexpr#5\relax} {\unexpanded\expandafter{\HardWrapSetup}} {\noexpand\MessageBreak} {##1}% }% \expandafter\edef\csname #2@warning@noline\endcsname##1{% \noexpand\HardWrap {\@nameuse{hw@#1@warning@noline}{#3}} {\number\numexpr#5\relax} {\unexpanded\expandafter{\HardWrapSetup}} {\noexpand\MessageBreak} {##1}% }% % \end{macrocode} % And finally errors. % % In addition to the \meta{info} and \meta{warning} lengths, % the \cs{PackageError} macro allows for % additional text to be displayed when the user requests it. This text % doesn't have anything prepended to each line, so the length of this text is % the same as $\textit{max\_print\_line}$. % \begin{macrocode} \expandafter\edef\csname #2@error\endcsname##1##2{% \noexpand\HardWrap {\xdef\noexpand\hw@tempa} {\number\numexpr#5\relax} {\unexpanded\expandafter{\HardWrapSetup}} {\MessageBreak} {\MessageBreak ##1}% \noexpand\HardWrap {\xdef\noexpand\hw@tempb} {\the\hw@maxprintline} {\unexpanded\expandafter{\HardWrapSetup}} {\MessageBreak} {\MessageBreak ##2}% \unexpanded{% \@nameuse{hw@#1@error}{#3}{\hw@tempa}{\hw@tempb}% }% }% } % \end{macrocode} % Here are our wrappers for \cs{ClassInfo} \etal, which are % used above to generalise the code a little. Note that these macros are % \cs{protected}, which allows them to be used in an expanding context % without a preceding \cs{noexpand}. % \begin{macrocode} \protected\def\hw@class@info #1#2{\ClassInfo {#1}{#2\hw@suffix}} \protected\def\hw@class@info@noline #1#2{\ClassInfo {#1}{#2\@gobbletwo}} \protected\def\hw@class@warning #1#2{\ClassWarning{#1}{#2\hw@suffix}} \protected\def\hw@class@warning@noline#1#2{\ClassWarning{#1}{#2\@gobbletwo}} \protected\def\hw@class@error #1#2{\ClassError {#1}{#2\@gobble}} % \end{macrocode} % And package messages: % \begin{macrocode} \protected\def\hw@package@info #1#2{\PackageInfo {#1}{#2\hw@suffix}} \protected\def\hw@package@info@noline #1#2{\PackageInfo {#1}{#2\@gobbletwo}} \protected\def\hw@package@warning #1#2{\PackageWarning{#1}{#2\hw@suffix}} \protected\def\hw@package@warning@noline#1#2{\PackageWarning{#1}{#2\@gobbletwo}} \protected\def\hw@package@error #1#2{\PackageError {#1}{#2\@gobble}} % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \part{Test suite} % % {\catcode`\%=14\input{hardwrap.tests}} % % \begin{macrocode} %\documentclass{article} %\usepackage{hardwrap,qstest} %\begin{document} %<*tests> % \end{macrocode} % % \begin{macrocode} \gdef\LIPSUM{Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna. Donec vehicula augue eu neque.} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{basics}{} \HardWrap{\xdef\TMP}{50}{}{NEWLINE}{aaa bbb ccc} \Expect*{\TMP}{aaa bbb ccc} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{newline}{} \HardWrap{\xdef\TMP}{50}{}{NEWLINE}{aaa \\ bbb ccc} \Expect*{\TMP}{aaa NEWLINEbbb ccc} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{noexpand/protect/string}{} \HardWrap{\xdef\TMP}{100}{}{NEWLINE}{% \string\section\ and \protect\subsection\ and \noexpand\paragraph\ and the rest} \Expect*{\TMP} *{\string\section\space and \string\subsection\space and \string\paragraph\space and the rest} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{ensure no wayward spaces}{} \newbox\myboxa \newbox\myboxb \setbox\myboxa=\hbox{xx} \setbox\myboxb=\hbox{x% \HardWrap{\xdef\TMP}{50}{}{NEWLINE}{\LIPSUM}% x} \Expect*{\the\wd\myboxa}*{\the\wd\myboxb} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{deal with explicit newlines}{} \HardWrap{\xdef\TMP}{50}{}{NEWLINE}{aaa bbb^^Jccc}% \Expect*{\TMP} *{aaa bbbNEWLINEccc} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{print braces properly}{} \begingroup \escapechar=-1 \xdef\EXPECT{a bb ccc dddd\string\{ eeeeeNEWLINEffffff\string\} ggggg hhhh} \endgroup \HardWrap{\xdef\TMP}{20}{}{NEWLINE}{a bb ccc dddd{ eeeee ffffff} ggggg hhhh}% \Expect*{\TMP}*{\EXPECT} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{print braces properly II}{} \begingroup \escapechar=-1 \xdef\EXPECT{a bb ccc dddd\string\{ eeeeeNEWLINEffffff \string\}ggggg hhhh} \endgroup \HardWrap{\xdef\TMP}{20}{}{NEWLINE}{a bb ccc dddd{ eeeee ffffff }ggggg hhhh}% \Expect*{\TMP}*{\EXPECT} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{print braces properly III}{} \begingroup \escapechar=-1 \xdef\EXPECT{a bb ccc dddd \string\{eeeeeNEWLINEffffff\string\} ggggg hhhh} \endgroup \HardWrap{\xdef\TMP}{20}{}{NEWLINE}{a bb ccc dddd {eeeee ffffff} ggggg hhhh}% \Expect*{\TMP}*{\EXPECT} \end{qstest} % \end{macrocode} % % \begin{macrocode} \begin{qstest}{trailing newline bug}{} \HardWrap{\xdef\TMP}{20}{}{N}{a\\b\\c\\}% \Expect*{\TMP}*{aNbNcN} \end{qstest} % \end{macrocode} % % \GenerateLogMacros{package}[HW]{hardwrap} % \GenerateLogMacros{class}[HWC]{hardwrap} % ^^A\HW@error{Please ignore this error!\\ I'm only testing things out.}{(Go away.)} % \HW@info{\LIPSUM} % \HWC@info@noline{\LIPSUM} % \HW@warning{\LIPSUM} % \HWC@warning@noline{\LIPSUM} % \HW@warning{Terminal spaces\MessageBreak used to\\ cause an infinite loop! No more } % \HW@warning{\space Testing\space\space\space spaces.\space} % \HW@warning{Hello!\MessageBreak This is an example of the hardwrap logging macro. Lets hope that it works properly and wrap our text to just the right length. (These words should reach all the way until the end of TeX's hard-wrapped log file output.) If not, panic!} % % \typeout{Note that if we're inserting manual line breaks, we can only reach column 78:} % \typeout{123456789012345678901234567890123456789012345678901234567890123456789012345678^^J123} % \typeout{1234567890123456789012345678901234567890123456789012345678901234567890123456789^^J123} % % \HW@info{Testing} % % % \HardWrap{\PackageWarning{foobar}}{50}{\HardWrapSetup}{\MessageBreak}{^^A % Sed feugiat. Cum sociis natoque penatibus et % magnis dis parturient montes, nascetur ridiculus mus. Ut % pellentesque augue sed urna. Vestibulum diam eros, fringilla et, % consectetuer eu, nonummy id, sapien. Nullam at lectus. In sagittis % ultrices mauris. Curabitur malesuada erat sit amet massa. Fusce % blandit. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. % Nunc imperdiet justo nec dolor;} % % \PackageWarning{foobar}{^^A % Sed feugiat. Cum sociis natoque penatibus et % magnis dis parturient montes, nascetur ridiculus mus. Ut % pellentesque augue sed urna. Vestibulum diam eros, fringilla et, % consectetuer eu, nonummy id, sapien. Nullam at lectus. In sagittis % ultrices mauris. Curabitur malesuada erat sit amet massa. Fusce % blandit. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. % Nunc imperdiet justo nec dolor;} % \newwrite\textfile % \immediate\openout\textfile=\jobname.txt\relax % \HardWrap{\immediate\write\textfile}{50}{\HardWrapSetup}{^^J}{% % Sed feugiat. Cum sociis natoque penatibus et % magnis dis parturient montes, nascetur ridiculus mus. Ut % pellentesque augue sed urna. Vestibulum diam eros, fringilla et, % consectetuer eu, nonummy id, sapien. Nullam at lectus. In sagittis % ultrices mauris. Curabitur malesuada erat sit amet massa. Fusce % blandit. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. % Nunc imperdiet justo nec dolor.} % \closeout\textfile % % \begin{macrocode} % %\end{document} % \end{macrocode} % % \Finale % % \posttoc % % \typeout{*************************************************************} % \typeout{*} % \typeout{* To finish the installation you have to move the following} % \typeout{* file into a directory searched by TeX:} % \typeout{*} % \typeout{* \space\space\space hardwrap.sty} % \typeout{*} % \typeout{*************************************************************} % \endinput