% \iffalse meta-comment % % Copyright (C) 2016-2017 by Takahiro Ueda % % This file may be distributed and/or modified under the conditions of % the LaTeX Project Public License, either version 1.3 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.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % To typeset this document, type the following commands: % latex autobreak.dtx % makeindex -s gind.ist autobreak.idx % makeindex -s gglo.ist -o autobreak.gls autobreak.glo % latex autobreak.dtx % latex autobreak.dtx % %<*ignore> \def\nameofplainTeX{plain} \ifx\fmtname\nameofplainTeX\else \expandafter\begingroup \fi % %<*install> \input docstrip.tex \keepsilent \askforoverwritefalse \preamble This is a generated file. Copyright (C) 2016-2017 by Takahiro Ueda This file may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 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.3 or later is part of all distributions of LaTeX version 2005/12/01 or later. \endpreamble \generate{ \usedir{tex/latex/autobreak} \file{\jobname.sty}{\from{\jobname.dtx}{package}} } % %<*ignore> \iffalse % %<*install> \obeyspaces \Msg{*************************************************************} \Msg{* *} \Msg{* To finish the installation you have to move the following *} \Msg{* file into a directory searched by TeX: *} \Msg{* *} \Msg{* autobreak.sty *} \Msg{* *} \Msg{* To produce the documentation run the file autobreak.dtx *} \Msg{* through LaTeX. *} \Msg{* *} \Msg{* Happy TeXing! *} \Msg{* *} \Msg{*************************************************************} \endbatchfile % %<*ignore> \fi \generate{ \file{\jobname.ins}{\from{\jobname.dtx}{install}} } \ifx\fmtname\nameofplainTeX \expandafter\endbatchfile \else \expandafter\endgroup \fi % %<*driver> \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage{lmodern} \usepackage{color} \usepackage{hypdoc} \usepackage{amsmath} \usepackage{autobreak} \EnableCrossrefs \CodelineIndex \RecordChanges \allowdisplaybreaks % The default value of IndexColumns=3 never fits in pages. \setcounter{IndexColumns}{2} \definecolor{hilite}{rgb}{0.2,0.4,0.7} \makeatletter \renewcommand{\HDorg@theCodelineNo}{% \textcolor{hilite}{\rmfamily\scriptsize\arabic{CodelineNo}}} \makeatother \providecommand\env[1]{\texttt{#1}} \providecommand\pkg[1]{\textsf{#1}} \usepackage{fancyvrb} \edef\examplefilename{\jobname.tmp} \newenvironment{example}{% \VerbatimEnvironment \begin{VerbatimOut}[gobble=2]{\examplefilename}% }{% \end{VerbatimOut}% \smallskip \noindent \begin{list}{}{}\item \begin{minipage}[t]{0.45\linewidth}% \VerbatimInput{\examplefilename}% \end{minipage}% \begin{minipage}[t]{0.5\linewidth}% \input{\examplefilename}% \end{minipage}% \end{list}% \smallskip \noindent } \newenvironment{example*}{% \VerbatimEnvironment \begin{VerbatimOut}[gobble=2]{\examplefilename}% }{% \end{VerbatimOut}% \smallskip \noindent \begin{list}{}{}\item \begin{minipage}[t]{0.95\linewidth}% \VerbatimInput{\examplefilename}% \end{minipage}% \end{list}% \smallskip \noindent } \newenvironment{example**}{% \VerbatimEnvironment \begin{VerbatimOut}[gobble=2]{\examplefilename}% }{% \end{VerbatimOut}% \smallskip \noindent \begin{list}{}{}\item \begin{minipage}[t]{0.95\linewidth}% \VerbatimInput{\examplefilename}% \end{minipage} \\ \begin{minipage}[t]{0.95\linewidth}% \input{\examplefilename}% \end{minipage}% \end{list}% \smallskip \noindent } % decl from ltxguide[2001/05/28] \newenvironment{decl}[1][]% {\par\small\addvspace{4.5ex plus 1ex}% \vskip -\parskip \ifx\relax#1\relax \def\@decl@date{}% \else \def\@decl@date{\NEWfeature{#1}}% \fi \noindent\hspace{-\leftmargini}% \begin{tabular}{|l|}\hline\ignorespaces}% {\\\hline\end{tabular}\nobreak\@decl@date\par\nobreak \vspace{2.3ex}\vskip -\parskip} \newcommand\NumberedBox[1]{% \, \framebox[25pt]{#1} \,% } \newcommand\LongerNumberedBox[1]{% \, \framebox[30pt]{#1} \,% } \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \CheckSum{409} % % \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 \~} % % \GetFileInfo{\jobname.sty} % % \title{The \pkg{autobreak} package\thanks{This document corresponds % to \pkg{autobreak}~\fileversion, dated \filedate.}} % \author{Takahiro Ueda} % % \date{23 February 2017} % % \maketitle % % \begin{abstract} % This package implements a simple mechanism of line/page breaking % within the \env{align} environment of the \pkg{amsmath} package; new % line characters are considered as possible candidates for the breaks % and the package tries to put breaks at adequate places. % It is suitable for computer-generated long formulae with many terms. % \end{abstract} % % \changes{v0.1}{2016/06/03}{Initial version} % % \tableofcontents % % \section{Introduction} % % Sometimes people want to put long formulae in their documents, which % do not fit in a line and may span over multiple pages. % The following is an equation of explicitly writing down the first 50 % terms in the sum of the well-known Basel problem: % \begin{align} % \begin{autobreak} % \zeta(2) = % 1 % + \frac{1}{4} % + \frac{1}{9} % + \frac{1}{16} % + \frac{1}{25} % + \frac{1}{36} % + \frac{1}{49} % + \frac{1}{64} % + \frac{1}{81} % + \frac{1}{100} % + \frac{1}{121} % + \frac{1}{144} % + \frac{1}{169} % + \frac{1}{196} % + \frac{1}{225} % + \frac{1}{256} % + \frac{1}{289} % + \frac{1}{324} % + \frac{1}{361} % + \frac{1}{400} % + \frac{1}{441} % + \frac{1}{484} % + \frac{1}{529} % + \frac{1}{576} % + \frac{1}{625} % + \frac{1}{676} % + \frac{1}{729} % + \frac{1}{784} % + \frac{1}{841} % + \frac{1}{900} % + \frac{1}{961} % + \frac{1}{1024} % + \frac{1}{1089} % + \frac{1}{1156} % + \frac{1}{1225} % + \frac{1}{1296} % + \frac{1}{1369} % + \frac{1}{1444} % + \frac{1}{1521} % + \frac{1}{1600} % + \frac{1}{1681} % + \frac{1}{1764} % + \frac{1}{1849} % + \frac{1}{1936} % + \frac{1}{2025} % + \frac{1}{2116} % + \frac{1}{2209} % + \frac{1}{2304} % + \frac{1}{2401} % + \frac{1}{2500} % + \dots % \end{autobreak} % \end{align} % The above example might seem nonsense, but putting long formulae may % have a meaning in some cases and become inevitable for completeness of % documents, writing self-contained papers, or just to impress readers. % They are typically generated as outputs of computer algebra systems, % and would have the form of a sum of many terms while each term is % short. % % Then, the question is how to break long formulae in such a way that % the expressions do not make any overfull lines for \LaTeX{}. % Certainly, one can attempt to manually insert line breaks by trial and % error, checking whether \LaTeX{} warns overfull lines, and this % process could be automatized by external scripts at some extent. % A shortcoming of such `manual' approaches is that line breaks have to % be reexamined whenever the layout of the document is changed, e.g., % replacing the document class or reusing existing equations into % another document with a different format. % % The goal of the \pkg{autobreak} package is to give a reasonably simple % solution for (semi-)automatic line breaking of long formulae within % \LaTeX{}^^A % \footnote{^^A % There is another package \pkg{breqn} % (\url{https://www.ctan.org/pkg/breqn}), which adopts a more % automatic fashion and is useful for more sophisticated line % breaking, unless you get ``Dimension too large'' error for really % big expressions. % }. % % \section{Usage} % % The \pkg{autobreak} package is supposed to be used together with the % \pkg{amsmath} package^^A % \footnote{^^A % \url{https://www.ctan.org/pkg/amsmath}. % }^^A % \footnote{^^A % Actually \pkg{autobreak} internally loads \pkg{amsmath}, but it is % still a good practice to explicitly include all packages providing % macros used in your document. % }: % \begin{example*} % \usepackage{amsmath} % \usepackage{autobreak} % \end{example*} % When your document contains long equations over multiple pages, % you might want to use \cs{allowdisplaybreaks} of \pkg{amsmath} % package: % \begin{example*} % \allowdisplaybreaks % \end{example*} % % \begin{decl} % |\begin{autobreak}| \\ % \meta{long-equations} \\ % |\end{autobreak}| % \end{decl} % \SpecialEnvIndex{autobreak} % The \env{autobreak} environment is used for breaking lines in long % formulae in the \env{align} environment of \pkg{amsmath}^^A % \footnote{^^A % Technically, \env{align} (with \cs{notag} to suppress equation % numbers except the last line) is the only option we can use for % page-break aligned equations within \pkg{amsmath} because % \env{split}, \env{gathered}, \env{aligned} and \env{alginedat} do % not allow page breaking. % \env{dmath} of \env{breqn} with \cs{eqinterlinepenalty}\texttt{=0} % allows page breaking, but may fail to find a reasonable tag place. % }. % \begin{example} % \begin{align} % \begin{autobreak} % \zeta(3) = % 1 % + \frac{1}{8} % + \frac{1}{27} % + \frac{1}{64} % + \frac{1}{125} % + \frac{1}{216} % + \frac{1}{343} % + \frac{1}{512} % + \frac{1}{729} % + \frac{1}{1000} % + \frac{1}{1331} % + \frac{1}{1728} % + \frac{1}{2197} % + \frac{1}{2744} % + \frac{1}{3375} % + \frac{1}{4096} % + \frac{1}{4913} % + \frac{1}{5832} % + \frac{1}{6859} % + \frac{1}{8000} % + \dots % \end{autobreak} % \end{align} % \end{example} % The magic happens from the simple fact that \env{autobreak} interprets % all new line characters appearing between |\begin{autobreak}| and % |\end{autobreak}| as \textit{breakable points}, at which any line % breaks can be logically inserted. To be more exact, the first % non-empty block, separated from the rest by a new line character, % determines the indentation of the successive lines. Then % \env{autobreak} tries to fill the line with the rest of the blocks, % and puts a line break when they do not fit in a line. This is % clarified by the following example: % \begin{example} % \begin{align} % \begin{autobreak} % \NumberedBox{1} % \NumberedBox{2} % \NumberedBox{3} % \NumberedBox{4} % \NumberedBox{5} % \NumberedBox{6} % \NumberedBox{7} % \NumberedBox{8} % \NumberedBox{9} % \NumberedBox{10} % \NumberedBox{11} % \end{autobreak} % \end{align} % \end{example} % % It is also possible to put more than one \env{autobreak} in one % \env{align}: % \begin{example} % \begin{align} % \begin{autobreak} % \NumberedBox{1} = % \NumberedBox{2} % + \NumberedBox{3} % + \NumberedBox{4} % + \NumberedBox{5} % + \NumberedBox{6} % + \NumberedBox{7} % + \NumberedBox{8} % + \NumberedBox{9} % + \NumberedBox{10} , % \end{autobreak} % \\ % \begin{autobreak} % \LongerNumberedBox{1} = % \NumberedBox{2} % + \NumberedBox{3} % + \NumberedBox{4} % + \NumberedBox{5} % + \NumberedBox{6} % + \NumberedBox{7} % + \NumberedBox{8} % + \NumberedBox{9} % + \NumberedBox{10} . % \end{autobreak} % \end{align} % \end{example} % For a technical reason, it often requires more than one run of % \LaTeX{}, and in such cases one will get informed by the following % warning: % \begin{example*} % Package autobreak Warning: Layout may have changed. % (autobreak) Rerun to get layout correct. % \end{example*} % In the next run, the layout of the equations will be corrected. % % \begin{decl} % |\MoveEqLeft|\oarg{number} % \end{decl} % This command is desinged to work like \cs{MoveEqLeft} of % the \pkg{mathtools} package^^A % \footnote{^^A % \url{https://www.ctan.org/pkg/mathtools}. % }. If it is put at the beginning of an \env{autobreak} environment, % then all subsequent lines after the first line are indented by 2 em % (the default value). % \begin{example} % \begin{align} % \begin{autobreak} % \MoveEqLeft % (n_1+n_2+n_3+n_4)^3 = % n_1^3 % + 3 n_1^2 n_2 % + 3 n_1 n_2^2 % + n_2^3 % + 3 n_1^2 n_3 % + 6 n_1 n_2 n_3 % + 3 n_2^2 n_3 % + 3 n_1 n_3^2 % + 3 n_2 n_3^2 % + n_3^3 % + 3 n_1^2 n_4 % + 6 n_1 n_2 n_4 % + 3 n_2^2 n_4 % + 6 n_1 n_3 n_4 % + 6 n_2 n_3 n_4 % + 3 n_3^2 n_4 % + 3 n_1 n_4^2 % + 3 n_2 n_4^2 % + 3 n_3 n_4^2 % + n_4^3 . % \end{autobreak} % \end{align} % \end{example} % The indent width can be changed by an optional argument of % the command. % % \begin{decl} % |\everybeforeautobreak| \marg{tokens} \\ % |\everyaftereautobreak| \marg{tokens} % \end{decl} % \SpecialUsageIndex{\everybeforeautobreak} % \SpecialUsageIndex{\everyafterautobreak} % They specify token lists inserted before and after automatically % inserted line breaks in \env{autobreak}. For example, % \begin{example**} % \begin{align} % \everyafterautobreak{\times} % \begin{autobreak} % \cos\left(\frac{\pi x}{2}\right) = % \left(1-x^2\right) % \left(1-\frac{x^2}{9}\right) % \left(1-\frac{x^2}{25}\right) % \left(1-\frac{x^2}{49}\right) % \left(1-\frac{x^2}{81}\right) % \left(1-\frac{x^2}{121}\right) % \left(1-\frac{x^2}{169}\right) % \left(1-\frac{x^2}{225}\right) % \left(1-\frac{x^2}{289}\right) % \left(1-\frac{x^2}{361}\right) % \left(1-\frac{x^2}{441}\right) % \dots % \end{autobreak} % \end{align} % \end{example**} % % \section{Caveats} % % Because \env{autobreak} tries to insert line breaks at any of new line % characters, you must not make any new lines at which the line cannot % be broken^^A % \footnote{^^A % You may put "\%" at the end of the line to avoid a new line. % }. % For example % \begin{example*} % \begin{align} % \begin{autobreak} % x = % % A problematic line break. % \frac{1} % {2} . % \end{autobreak} % \end{align} % \end{example*} % gives an error in the typesetting: % \begin{example*} % ! Missing } inserted. % % } % l.8 \end{align} % \end{example*} % % Putting `|\\|' or `|&|' inside \env{autobreak}, which tries to insert % these special stuffs automatically, also causes typesetting errors. % % The \env{autobreak} environment uses \cs{linewidth} as the maximum % width that expressions in its body can occupy. There is no way for % \env{autobreak} to know how much other formulae consume the space % outside it. Therefore it fails to determine the adequate maximum % width when there are expressions outside \env{autobreak} and % then \LaTeX{} gives overfull line warnings: % \begin{example*} % \begin{align} % \text{some stuff outside autobreak} % \begin{autobreak} % \text{LHS} = % ... % \end{autobreak} . % Even just a "." can be problematic. % \end{align} % % May give overfull line warnings % \end{example*} % % One may want to separate long formulae from the main document file to % other files and include them via \cs{input}\marg{file}, for example, % \begin{example*} % \begin{align} % \begin{autobreak} % \input{longeqn.inc} % It works! % \end{autobreak} % \end{align} % % \begin{align} % \begin{autobreak} % lhs = % \input{longrhs.inc} % It also works! % . % \end{autobreak} % \end{align} % \end{example*} % The current version of \env{autobreak} supports these cases: the file % content of \cs{input}\marg{file} is expanded before recognizing the % lines, with the help of the \pkg{catchfile} package^^A % \footnote{^^A % \url{https://www.ctan.org/pkg/catchfile}. % }, % when it appears at the beginning of each line. But it does not support % \cs{input}\marg{file} in the middle of the lines: % \begin{example*} % \begin{align} % \begin{autobreak} % x + \input{longexpr.inc} % Sorry, it does not work. % \end{autobreak} % \end{align} % \end{example*} % The difficulty comes from the fact that it needs to be expanded before % \env{autobreak} scans lines. By the same reason, \env{autobreak} fails % to detect new lines defined inside macros^^A % \footnote{^^A % Actually, when the definition of \cs{foo} is parsed, the new line % characters inside it are usually lost. % }: % \begin{example*} % \newcommand{\foo}{ % a % + b % + c % + d % } % \begin{align} % \begin{autobreak} % \foo + \foo + \foo + \foo % No new lines can be detected. % \end{autobreak} % \end{align} % \end{example*} % % \StopEventually{^^A % \PrintChanges % \PrintIndex % } % % \section{Implementation} % % \begin{macrocode} %<*package> \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{autobreak}% [2017/02/23 v0.3 simple line breaking of long formulae] % \end{macrocode} % % \subsection{Registers and constants} % % \begin{macro}{\everybeforeautobreak} % The list of tokens that gets inserted before every line break generated % by \env{autobreak}. % \begin{macrocode} \newtoks\everybeforeautobreak % \end{macrocode} % \end{macro} % % \begin{macro}{\everyafterautobreak} % The list of tokens that gets inserted after every line break generated % by \env{autobreak}. % \begin{macrocode} \newtoks\everyafterautobreak % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@alltoks} % The token register to store the whole result of \env{autobreak}. % \begin{macrocode} \newtoks\@autobreak@alltoks % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@linetoks} % The token register for the current line. % \begin{macrocode} \newtoks\@autobreak@linetoks % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@lhswidth} % The width of the current left-hand side. % \begin{macrocode} \newdimen\@autobreak@lhswidth % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@rhswidth} % The width of the current right-hand side. % \begin{macrocode} \newdimen\@autobreak@rhswidth % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@maxlhswidth} % The width of the longest left-hand side occupied. Affected by the % |.aux| file generated in the previous run. % \begin{macrocode} \newdimen\@autobreak@maxlhswidth % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@realmaxlhswidth} % The width of the longest left-hand side occupied. Not affected by the % |.aux| file generated in the previous run. % \begin{macrocode} \newdimen\@autobreak@realmaxlhswidth % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@maxrhswidth} % The maximum width that the right-hand sides can occupy. % \begin{macrocode} \newdimen\@autobreak@maxrhswidth % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@newlinechar} % The macro representing an active |^^M|. % \begin{macrocode} \begingroup \catcode`\^^M=\active \gdef\@autobreak@newlinechar{^^M} \endgroup % \end{macrocode} % \end{macro} % % \subsection{Interaction with \texttt{.aux} files} % % When there are two or more \env{autobreak} in one \env{align}, each % \env{autobreak} has to know the maximum width of the left-hand side of % the all \env{autobreak} in the same \env{align}. Instead of violating % `causality' (e.g., how \LaTeX{} parses a file from the beginning to % the end), we use |.aux| file to store the maximum left-hand side % width, which provides the correct value in the next run. % % \begin{macro}{\if@autobreak@invalidlayout} % The switch to be turned on when an invalid layout is detected. % \begin{macrocode} \newif\if@autobreak@invalidlayout \@autobreak@invalidlayoutfalse % \end{macrocode} % \end{macro} % Show a warning if the user needs to rerun. % \begin{macrocode} \AtEndDocument{% \if@autobreak@invalidlayout \if@filesw \PackageWarningNoLine{autobreak}{Layout may have changed. \MessageBreak Rerun to get layout correct}% \else \PackageWarningNoLine{autobreak}{Layout may be wrong}% \fi \fi } % \end{macrocode} % \begin{macro}{\@autobreak@getmaxlhswidth} % To be expanded to a value saved in |.aux| in the previous run, or % |0pt| if not found. % \begin{macrocode} \def\@autobreak@getmaxlhswidth#1{% \@ifundefined{@autobreak@w@#1}{% \z@ }{% \@nameuse{@autobreak@w@#1}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@setmaxlhswidth} % Called in |.aux|. % \begin{macrocode} \def\@autobreak@setmaxlhswidth#1#2{% \global\@namedef{@autobreak@w@#1}{#2}% } % \end{macrocode} % \end{macro} % % \begin{macro}{@autobreak@eqnindex} % The counter to identify each \env{align}. % \begin{macrocode} \newcounter{@autobreak@eqnindex} % \end{macrocode} % \end{macro} % % \begin{macro}{@autobreak@subeqnindex} % The counter to store the number of \env{autobreak} in an \env{align}. % \begin{macrocode} \newcounter{@autobreak@subeqnindex}[@autobreak@eqnindex]% % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@loadmaxlhswidth} % Loads \cs{@autobreak@maxlhswidth} for the next \env{align}. % \begin{macrocode} \def\@autobreak@loadmaxlhswidth{% \stepcounter{@autobreak@eqnindex}% \@autobreak@maxlhswidth=% \@autobreak@getmaxlhswidth{\arabic{@autobreak@eqnindex}}% \@autobreak@realmaxlhswidth=\z@ } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@savemaxlhswidth} % Saves \cs{@autobreak@realmaxlhswidth} for the next run. % \begin{macrocode} \def\@autobreak@savemaxlhswidth{% \ifnum\arabic{@autobreak@subeqnindex}>0 \ifdim\@autobreak@maxlhswidth=\@autobreak@realmaxlhswidth \else % \end{macrocode} % We have used the wrong value of \cs{@autobreak@maxlhswidth} (was too % much). Need to rerun. % \begin{macrocode} \global\@autobreak@invalidlayouttrue \fi % \end{macrocode} % Note that \cs{@autobreak@maxlhswidth} becomes problematic only when % two or more \env{autobreak} appear in one \env{align}. In the case % with one \env{autobreak}, the default value |0pt| is safe for the next % run. % \begin{macrocode} \ifnum\arabic{@autobreak@subeqnindex}>1 \if@filesw % \end{macrocode} % We should provide \cs{@autobreak@setmaxlhswidth} in |.aux|. % \begin{macrocode} \@ifundefined{@autobreak@auxinited}{% \immediate\write\@mainaux{% \string\providecommand \string\@autobreak@setmaxlhswidth[2]{}% }% \gdef\@autobreak@auxinited{}% }{}% \immediate\write\@auxout{% \string\@autobreak@setmaxlhswidth% {\arabic{@autobreak@eqnindex}}% {\the\@autobreak@realmaxlhswidth}% }% \fi \fi \fi } % \end{macrocode} % \end{macro} % % \subsection{Hacking \pkg{amsmath}} % % \begin{macrocode} \RequirePackage{amsmath} % \end{macrocode} % % \begin{macro}{\if@autobreak@newlinedef} % The switch to be turned on when \cs{@autobreak@newlinedef} applies. % \begin{macrocode} \newif\if@autobreak@newlinedef \@autobreak@newlinedeffalse % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@newlinedef} % Installs the definition of |^^M| as a space. This is virtually % harmless in math mode. % \begin{macrocode} \begingroup \catcode`\^^M=\active \gdef\@autobreak@newlinedef{% \def^^M{ }% \@autobreak@newlinedeftrue } \endgroup % \end{macrocode} % \end{macro} % % \begin{macro}{\collect@body} % We need to override \cs{collect@body} such that it keeps |^^M|. % \begin{macrocode} \def\collect@body#1{% \@envbody={\expandafter#1\expandafter{\the\@envbody}}% \edef\process@envbody{% \the\@envbody\noexpand\end{\@currenvir}% }% \@envbody=\@emptytoks \def\begin@stack{b}% \begingroup % \end{macrocode} % Actually, the following three lines need to be inserted to the % original code. % \begin{macrocode} \if@autobreak@newlinedef \catcode`\^^M=\active \fi \expandafter\let\csname\@currenvir\endcsname=\collect@@body \edef\process@envbody{% \expandafter\noexpand\csname\@currenvir\endcsname }% \process@envbody } % \end{macrocode} % \end{macro} % % \begin{environment}{align} % Hack \env{align} of \pkg{amsmath}. % \begin{macrocode} \let\@autobreak@oldstart@align=\start@align \def\start@align{% \@autobreak@loadmaxlhswidth \@autobreak@newlinedef \@autobreak@oldstart@align } % \end{macrocode} % \begin{macrocode} \let\@autobreak@oldendalign=\endalign \def\endalign{% \@autobreak@savemaxlhswidth \@autobreak@oldendalign } % \end{macrocode} % \end{environment} % % \subsection{\env{autobreak} environment} % % \begin{environment}{autobreak} % Checks if we are in \env{align} (and \cs{@autobreak@newlinedef} is % applied), increments the counter and collects its body via % \cs{collect@body}. % \begin{macrocode} \newenvironment{autobreak}{% \if@autobreak@newlinedef \else \PackageError{autobreak}{% autobreak is not allowed here% }{% Use autobreak inside align. }% \fi \stepcounter{@autobreak@subeqnindex}% \collect@body\@autobreak }{} % \end{macrocode} % \end{environment} % % \begin{macro}{\@autobreak} % Called from \cs{collect@body}. The parameter |#1| is the whole body. % It takes also |#2| and |#3|, which are always \cs{end} and % |autobreak|, to remove them from the successive tokens. % \begin{macrocode} \def\@autobreak#1#2#3{% % \end{macrocode} % First, close the group of \env{autobreak}. % \begin{macrocode} \end{autobreak}% % \end{macrocode} % Then parse the given body of the environment and construct lines to be % passed to \env{align}. % \begin{macrocode} \@autobreak@init \def\@tempa{\expandafter\@autobreak@scanline \@autobreak@newlinechar#1}% \expandafter\@tempa\@autobreak@newlinechar\@autobreak@end } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@init} % Initialization. % \begin{macrocode} \def\@autobreak@init{% \@autobreak@alltoks={}% \@autobreak@linetoks={}% \@autobreak@lhswidth=\z@ \let\MoveEqLeft=\@autobreak@MoveEqLeft } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@end} % Finalization. It generates the whole lines in one go. % \begin{macrocode} \def\@autobreak@end{% \expandafter\@autobreak@addtoks\expandafter\@autobreak@alltoks \expandafter{\the\@autobreak@linetoks}% \the\@autobreak@alltoks } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@scanline} % Takes a line from the input stream. Here a line ends with |^^M|. % \begin{macrocode} \begingroup \catcode`\^^M=\active \gdef\@autobreak@scanline#1^^M{\@autobreak@scanline@{#1}} \endgroup % \end{macrocode} % If the next token is a punctuation, then we merge it into the current % line. (Otherwise it can make a line only with a period, for example). % \begin{macrocode} \def\@autobreak@scanline@#1{% \@autobreak@ifnextpunct{% \@autobreak@scanline@gobble{#1}% }{% \@autobreak@scanline@@{#1}% }% } % \end{macrocode} % A helper macro of \cs{@ifnextpunct}\marg{if-yes}\marg{if-no}. % \begin{macrocode} \def\@autobreak@ifnextpunct#1#2{% \@ifnextchar.{% #1% }{% \@ifnextchar,{% #1% }{% \@ifnextchar;{% #1% }{% \@ifnextchar:{% #1% }{% #2% }% }% }% }% } % \end{macrocode} % Merge punctuations as possible (usually there is only one period in a % line, though). % \begin{macrocode} \def\@autobreak@scanline@gobble#1#2{% \@autobreak@ifnextpunct{% \@autobreak@scanline@gobble{#1#2}% }{% \@autobreak@scanline@@{#1#2}% }% } % \end{macrocode} % Pass the current line to \cs{@autobreak@processline}. Then, repeat % scanning lines until \cs{@autobreak@end} appears as the next token. % \begin{macrocode} \def\@autobreak@scanline@@#1{% \@autobreak@processline{#1}% \@ifnextchar\@autobreak@end{}{% \@autobreak@scanline@@@ }% } % \end{macrocode} % Catch \cs{MoveEqLeft}. % \changes{v0.3}{2017/02/23}{Add \cs{MoveEqLeft} command} % \begin{macrocode} \def\@autobreak@scanline@@@{% \@ifnextchar\MoveEqLeft{% \@autobreak@scanline@MoveEqLeft }{% \@autobreak@scanline@@@@ }% } % \end{macrocode} % The argument |#1| is \cs{MoveEqLeft}. This command accepts an % optional number. % \begin{macrocode} \def\@autobreak@scanline@MoveEqLeft#1{% \@ifnextchar[{% \@autobreak@scanline@MoveEqLeft@ }{% \@autobreak@scanline@MoveEqLeft@[2]% }% } % \end{macrocode} % \begin{macrocode} \def\@autobreak@scanline@MoveEqLeft@[#1]{% \ifdim#1\p@>\z@ \def\@tempa{\@autobreak@scanline@MvEqL@pos}% \else\ifdim#1\p@=\z@ \def\@tempa{\@autobreak@scanline@MvEqL@zero}% \else \def\@tempa{\@autobreak@scanline@MvEqL@neg}% \fi\fi \@tempa{#1}% } % \end{macrocode} % \begin{macrocode} \def\@autobreak@scanline@MvEqL@pos#1{% \def\@tempa{\expandafter\@autobreak@scanline\kern#1em}% \expandafter\@tempa\@autobreak@newlinechar\kern-#1em% } % \end{macrocode} % In the case with |#1| = 0, a special treatment is required because \\ % \cs{@autobreak@processline} ignores a zero width. Insert a very tiny % space. % \begin{macrocode} \def\@autobreak@scanline@MvEqL@zero#1{% \def\@tempa{\expandafter\@autobreak@scanline\kern1sp}% \expandafter\@tempa\@autobreak@newlinechar\kern-1sp% } % \end{macrocode} % In the case with |#1| < 0, put a very tiny space, and then put the % space with a positive width such that the first line is indented to % the right. % \begin{macrocode} \def\@autobreak@scanline@MvEqL@neg#1{% \def\@tempa{\expandafter\@autobreak@scanline\kern1sp}% \expandafter\@tempa\@autobreak@newlinechar\kern-1sp\kern-#1em% } % \end{macrocode} % One may expect \cs{input}\marg{file} in \env{autobreak} is expanded by % the file content and \env{autobreak} treats new lines in it correctly. % But it needs more work. Because handling of \cs{input} in the middle % of the lines is rather involved, for now we support only \cs{input} at % the beginning of each line (which is what sane people usually do). % This can be done via the \pkg{catchfile} package. % \begin{macrocode} \IfFileExists{catchfile.sty}{ \RequirePackage{catchfile} \def\@autobreak@scanline@@@@{% \@ifnextchar\input{% \@autobreak@scanline@input }{% \@autobreak@scanline }% }% }{ \def\@autobreak@scanline@@@@{% \@ifnextchar\input{% \PackageWarning{autobreak}{% Cannot handle new lines in a file via \protect\input, \MessageBreak which requires the catchfile package }% }% \@autobreak@scanline }% } % \end{macrocode} % The argument |#1| is \cs{input} and |#2| is the file name. % \begin{macrocode} \def\@autobreak@scanline@input#1#2{% \CatchFileDef\@tempa{#2}{\catcode`\^^M=\active}% \expandafter\@autobreak@scanline\@tempa } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@MoveEqLeft} % This definition is expanded only when \cs{@autobreak@scanline} cannot % detect \cs{MoveEqLeft} in an \env{autobreak} environment, in other % words, when it appears in the middle of a line. % \begin{macrocode} \def\@autobreak@MoveEqLeft{% \PackageError{autobreak}{% \protect\MoveEqLeft\space is not allowed here% }{% \protect\MoveEqLeft\space must be put at the beginning of an autobreak environment. }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@processline} % \changes{v0.2}{2016/07/03}{Fix space calculation around alignment % tabs} % Each line from \cs{autobreak@scanline} should be regarded as a `block' % in the equation. The first block (typically the left-hand side $+$ % `=') determines the indentation for the successive lines. From the % second block, try to append the block to the end of the line and % insert a line break if it does not fit in a line. Note that we measure % the widths of the blocks with putting |{}| around alignment tabs. % \begin{macrocode} \def\@autobreak@processline#1{% \ifdim\@autobreak@lhswidth=\z@ % \end{macrocode} % For the first block. The rest of the width for the right-hand sides % is determined from \cs{linewidth} and \cs{@autobreak@maxlhswidth}. % \begin{macrocode} \@autobreak@settowidth\@autobreak@lhswidth{#1{}}% \ifdim\@autobreak@lhswidth>\z@ \ifdim\@autobreak@lhswidth>\@autobreak@maxlhswidth \ifdim\@autobreak@maxlhswidth>\z@ % \end{macrocode} % The previous one used the wrong value of \cs{@autobreak@maxlhswidth} % (was too short). Need to rerun. % \begin{macrocode} \global\@autobreak@invalidlayouttrue \fi \global\@autobreak@maxlhswidth=\@autobreak@lhswidth \fi \ifdim\@autobreak@lhswidth>\@autobreak@realmaxlhswidth \global\@autobreak@realmaxlhswidth=\@autobreak@lhswidth \fi \@autobreak@maxrhswidth=\linewidth \advance\@autobreak@maxrhswidth by -\@autobreak@maxlhswidth \@autobreak@alltoks={#1{}&}% \fi \else % \end{macrocode} % For the rest of the blocks. % \begin{macrocode} \@autobreak@settowidth\@autobreak@rhswidth {{}\the\@autobreak@linetoks#1\the\everybeforeautobreak}% \ifdim\@autobreak@rhswidth>\@autobreak@maxrhswidth % \end{macrocode} % Adding the next block gives an overfull line. Need a line break. % \begin{macrocode} \edef\@tempa{\the\@autobreak@linetoks\the\everybeforeautobreak}% \expandafter\@autobreak@addtoks\expandafter\@autobreak@alltoks \expandafter{\@tempa\notag\\&}% \@autobreak@linetoks=\everyafterautobreak \fi \@autobreak@addtoks\@autobreak@linetoks{#1}% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@addtoks} % Appends |#2| to the token register |#1|. % \begin{macrocode} \def\@autobreak@addtoks#1#2{% #1=\expandafter{\the#1#2}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@autobreak@settowidth} % Same as \cs{settowidth} but in math mode. We assume \cs{displaystyle}. % (Anyway \env{align} issues \cs{displaystyle} at the beginning of every % cell.) % \begin{macrocode} \def\@autobreak@settowidth#1#2{% \settowidth#1{$\displaystyle#2$}% } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % \Finale \endinput