23a78dc41a6f46d7dd1026ba9af13573755acf50
[conteq.git] / conteq.dtx
1 % \iffalse meta-comment
2 % !TEX program  = pdfLaTeX
3 %<*internal>
4 \iffalse
5 %</internal>
6 %<*readme>
7 ----------------------------------------------------------------
8 conteq --- continued equalities
9 E-mail: mail@joachim-breitner.de
10 Released under the LaTeX Project Public License v1.3c or later
11 See http://www.latex-project.org/lppl.txt
12 ----------------------------------------------------------------
13
14 This package allows you to write an continued equality such as
15
16     \begin{conteq}
17     e^{\pi\cdot i} \\
18     = -1 & Euler's formula \\
19     < 0 & this is an inequality \\ 
20     < \sqrt 3 \\
21     = \int e^{-x^2} dx & this is due to Gauss.
22     \end{conteq}
23
24 in a declarative manner and easily switch between various layouts afterwards.
25 %</readme>
26 %<*internal>
27 \fi
28 \def\nameofplainTeX{plain}
29 \ifx\fmtname\nameofplainTeX\else
30   \expandafter\begingroup
31 \fi
32 %</internal>
33 %<*install>
34 \input docstrip.tex
35 \keepsilent
36 \askforoverwritefalse
37 \preamble
38 ----------------------------------------------------------------
39 conteq --- continued equalities
40 E-mail: mail@joachim-breitner.de
41 Released under the LaTeX Project Public License v1.3c or later
42 See http://www.latex-project.org/lppl.txt
43 ----------------------------------------------------------------
44
45 \endpreamble
46 \postamble
47
48 Copyright (C) 2013 by Joachim Breitner <mail@joachim-breitner.de>
49
50 This work may be distributed and/or modified under the
51 conditions of the LaTeX Project Public License (LPPL), either
52 version 1.3c of this license or (at your option) any later
53 version.  The latest version of this license is in the file:
54
55 http://www.latex-project.org/lppl.txt
56
57 This work is "maintained" (as per LPPL maintenance status) by
58 Joachim Breitner.
59
60 This work consists of the file  conteq.dtx
61 and the derived files           conteq.ins,
62                                 conteq.pdf and
63                                 conteq.sty.
64
65 \endpostamble
66 \usedir{tex/latex/conteq}
67 \generate{
68   \file{\jobname.sty}{\from{\jobname.dtx}{package}
69                       \from{\jobname.dtx}{layouts}}
70 }
71 %</install>
72 %<install>\endbatchfile
73 %<*internal>
74 \generate{
75   \file{\jobname.ins}{\from{\jobname.dtx}{install}}
76 }
77 \nopreamble\nopostamble
78 \generate{
79   \file{README.txt}{\from{\jobname.dtx}{readme}}
80 }
81 \ifx\fmtname\nameofplainTeX
82   \expandafter\endbatchfile
83 \else
84   \expandafter\endgroup
85 \fi
86 %</internal>
87 %<package>\NeedsTeXFormat{LaTeX2e}
88 %<package>\RequirePackage{expl3}
89 %<package>\ProvidesExplPackage
90 %<package>  {conteq}              % Package name
91 %<package>  {2013/05/23}          % Release date
92 %<package>  {0.1}                 % Release version
93 %<package>  {Various layouts for continued equalities} % Description
94 %
95 %<*driver>
96 \documentclass[full]{l3doc}
97 \usepackage[T1]{fontenc}
98 \usepackage{lmodern}
99 \usepackage{conteq}
100 %\usepackage[numbered]{hypdoc}
101 \EnableCrossrefs
102 \CodelineIndex
103 \RecordChanges
104 \begin{document}
105   \DocInput{\jobname.dtx}
106 \end{document}
107 %</driver>
108 % \fi
109 %
110 % \GetFileInfo{\jobname.sty}
111 %
112 % \CheckSum{166}
113 %
114 %
115 %\title{^^A
116 %  \textsf{conteq} --- continued equalities\thanks{^^A
117 %    This file describes version \fileversion, last revised \filedate.^^A
118 %  }^^A
119 %}
120 %\author{Joachim Breitner\thanks{E-mail: mail@joachim-breitner.de}}
121 %
122 %\date{Released \filedate}
123 %
124 %\maketitle
125 %
126 %\changes{0.1}{2013/05/23}{Converted to DTX file}
127 %
128 %
129 % \section{Introduction}
130 %
131 % There are various ways to layout an continued equality that spans multiple lines and has explanations along some steps. Often, the best layout is not clear beforehand, as it depends on the sizes of the various elements, or implementing it adds too much noise to the actual formulas. This package provides an environment for continued equalities (or inequalities) that allows you to easily define and switch layouts.
132 %
133 % \section{Usage}
134 %
135 % \DescribeEnv{conteq}
136 % Our running example is the following continued equality:
137
138 % \begin{verbatim}
139 % \begin{conteq}
140 % e^{\pi\cdot i} \\
141 % = -1 & Euler's formula \\
142 % < 0 & this is an inequality \\ 
143 % < \sqrt 3 \\
144 % = \int e^{-x^2} dx & this is due to Gauss.
145 % \end{conteq}
146 % \end{verbatim}
147 %
148 % As you can see, the expressions of the continued equality are separated by |\\|, with equality signs (or other relations) at the beginning of all lines but the first. Some equalities also have explanations.
149
150 % The result of the above code is
151 % \begin{conteq}
152 % e^{\pi\cdot i} \\
153 % = -1 & Euler's formula \\
154 % < 0 & this is an inequality \\ 
155 % < \sqrt 3 \\
156 % = \int e^{-x^2} dx & this is due to Gauss.
157 % \end{conteq}
158 %
159 % The expressions are typeset in math mode, while the explanation is assumed to be regular text. The curly braces around the explanations come from the default |\ConteqExplStyle|.
160
161 % There are other layouts available, which you select with an optional parameter to |\begin{conteq}|, e.g.
162 % \begin{verbatim}
163 % \begin{conteq}[explline]
164 % [..]
165 % \end{conteq}
166 % \end{verbatim}
167
168 % The layouts defined by |conteq| are:
169
170 % \paragraph{plain} The default layout, shown above.
171
172 % \paragraph{explline} A layout that puts the explanations below the right-hand side of the equalty it is explaining. To be used when the explanations and righ-hand sides are long.
173 % \begin{conteq}[explline]
174 % e^{\pi\cdot i} \\
175 % = -1 & Euler's formula \\
176 % < 0 & this is an inequality \\ 
177 % < \sqrt 3 \\
178 % = \int e^{-x^2} dx & this is due to Gauss.
179 % \end{conteq}
180
181
182 % \paragraph{headline} Like plain, but the first expression is also vertically aligned with the right-hand sides.
183 % \begin{conteq}[headline]
184 % e^{\pi\cdot i} \\
185 % = -1 & Euler's formula \\
186 % < 0 & this is an inequality \\ 
187 % < \sqrt 3 \\
188 % = \int e^{-x^2} dx & this is due to Gauss.
189 % \end{conteq}
190
191 % \paragraph{onecolumn} A combination of \textbf{explline} and \textbf{headline} that puts everything in one column, for maximum space efficiency.
192 % \begin{conteq}[onecolumn]
193 % e^{\pi\cdot i} \\
194 % = -1 & Euler's formula \\
195 % < 0 & this is an inequality \\ 
196 % < \sqrt 3 \\
197 % = \int e^{-x^2} dx & this is due to Gauss.
198 % \end{conteq}
199
200 % \paragraph{oneline} A layout, more for demonstrational purposes, that ignores the explanations and puts everything in one line.
201 % \begin{conteq}[oneline]
202 % e^{\pi\cdot i} \\
203 % = -1 & Euler's formula \\
204 % < 0 & this is an inequality \\ 
205 % < \sqrt 3 \\
206 % = \int e^{-x^2} dx & this is due to Gauss.
207 % \end{conteq}
208
209 % \DescribeMacro{\ConteqSetDefaultLayout} You can change the default layout using |\ConteqSetDefaultLayout|\marg{layout}
210
211 % \section{Defining layouts}
212 %
213 % \DescribeMacro{\ConteqDefineLayout}
214 % To define a new layout you use |\ConteqDefineLayout|, which takes seven arguments:
215 % \begin{enumerate}
216 % \item The name of the layout,
217 % \item What to put before the continued equalities,
218 % \item the left-hand side of the first equality,
219 % \item the right-hand side of equalities without explanation,
220 % \item the right-hand side of equalities with explanation,
221 % \item the line separator and
222 % \item what to put after the continued equalities.
223 % \end{enumerate}
224 %
225 % For example the existing layouts are defined using
226 % \iffalse
227 %<*layouts>
228 % \fi
229 %    \begin{macrocode}
230
231 \ConteqDefineLayout
232     {plain}
233     {\begin{align*}}
234     { #1 }
235     { & #1 }
236     { & #1 && #2 }
237     { \\ }
238     {\end{align*}}
239 \ConteqSetDefaultLayout{plain}
240
241 \ConteqDefineLayout
242     {explline}
243     {\begin{align*}}
244     { #1 }
245     { & #1 }
246     { & #1 \\ & \mathrel{\phantom{=}} #2 }
247     { \\ }
248     {\end{align*}}
249
250 \ConteqDefineLayout
251     {headline}
252     {\begin{align*}}
253     { &\mathrel{\phantom{=}} #1 \\ }
254     { & #1 }
255     { & #1 && #2 }
256     { \\ }
257     {\end{align*}}
258  
259 \ConteqDefineLayout
260     {onecolumn}
261     {\begin{align*}}
262     { &\mathrel{\phantom{=}} #1 \\ }
263     { & #1 }
264     { & #1 \\ & \mathrel{\phantom{=}} #2 }
265     { \\ }
266     {\end{align*}}
267
268 \ConteqDefineLayout
269     {oneline}
270     {\[}
271     { #1 }
272     { #1 }
273     { #1 }
274     {}
275     {\]}
276
277 %    \end{macrocode}
278 %
279 % \section{Changing the explanation style}
280 %
281 % \DescribeMacro{\ConteqExplStyle}
282 % The explanation is formatted using the macro |\ConteqExplStyle|\marg{explanation}, which is by default defined as
283 %    \begin{macrocode}
284 \newcommand{\ConteqExplStyle}[1]{\{~#1~\}}
285 %    \end{macrocode}
286 %
287 % To change the style, simply redefine this macro using, for example:
288 % \begin{verbatim}
289 % \renewcommand{\ConteqExplStyle}{\textit{-- #1}}
290 % \end{verbatim}
291 %
292 %
293 % \section{Future work}
294 %
295 % This package is, at the time of writing, very new, so please le me know about problems you are having or features you are missing.
296 %
297 % One feature that I am considering is an auto-selection of layouts, so when you specify |\begin{conteq}[plain,explline,onecolumn]...\end{conteq}|, it will analyze the table and select, from your list of layouts, the first one that is ``ok'', where ``ok'' would be some layout-specific heuristic taking the size of the expressions and explanations as well as the current |\linewidth| into account. If you think that this would be useful to you, please let me know.
298 %
299 % \iffalse
300 %</layouts>
301 % \fi
302 %
303 %\StopEventually{^^A
304 %  \PrintChanges
305 %  \PrintIndex
306 %}
307 %
308
309 %
310 % \section{Implementation}
311 %
312 % \iffalse
313 %<*package>
314 % \fi
315 %
316 % \subsection{Package loading}
317
318 %    \begin{macrocode}
319 \RequirePackage{amsmath}
320 \RequirePackage{environ}
321 %    \end{macrocode}
322
323 % \subsection{Defining Messages}
324 %
325 %    \begin{macrocode}
326 \msg_new:nnn
327     {conteq}
328     {empty}
329     { \msg_warning_text:n{conteq}:~Empty~conteq~environment~\msg_line_context: }
330
331 \msg_new:nnn
332     {conteq}
333     {ignoreddata}
334     { \msg_warning_text:n{conteq}:~Ignored~text~\msg_line_context: }
335
336 \msg_new:nnn
337     {conteq}
338     {undefinedlayout}
339     { \msg_critical_text:n{conteq}:~Undefined~layout~``#1''~\msg_line_context: }
340 %    \end{macrocode}
341
342 % \subsection{Declaring local variables}
343 %
344 %    \begin{macrocode}
345 \tl_new:N \l_conteq_default_layout_tl
346 \tl_new:N \l_conteq_layout_tl
347 \tl_new:N \l_conteq_body_tl
348 \tl_new:N \l_conteq_lines_seq
349 \tl_new:N \l_conteq_cells_seq
350 \tl_new:N \l_conteq_head_tl
351 \tl_new:N \l_conteq_lastline_tl
352 \tl_new:N \l_conteq_rhs_tl
353 \tl_new:N \l_conteq_expl_tl
354 \tl_new:N \l_conteq_result_tl
355 %    \end{macrocode}
356
357 % \subsection{Layouts}
358 %
359 % \begin{macro}{\ConteqSetDefaultLayout}
360 % The code to set the default layout.
361 %    \begin{macrocode}
362 \cs_new_protected:Nn \conteq_set_default_layout:n {
363   \tl_set:Nn \l_conteq_default_layout_tl {#1}
364 }
365 \cs_new_eq:NN \ConteqSetDefaultLayout \conteq_set_default_layout:n
366 %    \end{macrocode}
367 % \end{macro}
368 %
369 % \begin{macro}{\ConteqDefineLayout}
370 % The code to define new layouts.
371 %    \begin{macrocode}
372 \cs_new_protected:Nn \conteq_define_layout:nnnnnnn {
373   \cs_new_protected:cn {conteq_#1_begin:} { #2 }
374   \cs_new_protected:cn {conteq_#1_lhs:n} { #3 }
375   \cs_new_protected:cn {conteq_#1_rhs_only:n} { #4 }
376   \cs_new_protected:cn {conteq_#1_rhs_expl:nn} { #5 }
377   \cs_new_protected:cn {conteq_#1_nl:} { #6 }
378   \cs_new_protected:cn {conteq_#1_end:} { #7 }
379 }
380 \cs_new_eq:NN \ConteqDefineLayout \conteq_define_layout:nnnnnnn
381 %    \end{macrocode}
382 % \end{macro}
383 %
384 % \subsection{Expansion utility function}
385
386 % \begin{macro}{\conteq_args_once:Nn, \conteq_args_once:NV, \conteq_args_once:Nnn, \conteq_args_once:NVV}
387 % For ease of debugging(?) we construct a token list that contains exactly the tokens that a programmer would enter to create the layout manually. For that we need some fine-grained control over expansion.
388 %
389 %    \begin{macrocode}
390 \cs_new:Npn \conteq_args_once:Nn #1#2 {
391    \exp_not:o {#1 {#2}}
392 }
393 \cs_generate_variant:Nn \conteq_args_once:Nn {NV}
394
395 \cs_new:Npn \conteq_args_once:Nnn #1#2#3 {
396    \exp_not:o {#1 {#2}{#3}}
397 }
398 \cs_generate_variant:Nn \conteq_args_once:Nnn {NVV}
399 %    \end{macrocode}
400 % \end{macro}
401 %
402 % \subsection{Main code}
403 %
404 % \begin{macro}{\conteq_print_line:nn}
405 % This macro splits and prints one line of the table. The second argument is either |\\| or, for the last line of the table, empty.
406 %    \begin{macrocode}
407 \cs_new_protected:Npn \conteq_print_line:Nnn #1#2#3 {
408   \seq_set_split:Nnn \l_conteq_cells_seq { & } {#2}
409   \seq_pop_left:NN \l_conteq_cells_seq \l_conteq_rhs_tl
410   \tl_clear:N \l_conteq_expl_tl
411   \seq_if_empty:NF \l_conteq_cells_seq {
412     \seq_pop_left:NN \l_conteq_cells_seq \l_conteq_expl_tl
413   }
414   \tl_if_blank:VTF \l_conteq_expl_tl {
415     \tl_put_right:Nx #1 {
416       \conteq_args_once:NV \conteq_rhs_only:n \l_conteq_rhs_tl
417     }
418   }{
419     \tl_set:Nx \l_tmpa_tl {\exp_not:N \text {\exp_not:N \ConteqExplStyle {\exp_not:V \l_conteq_expl_tl}}}
420     \tl_put_right:Nx #1 {
421       \conteq_args_once:NVV \conteq_rhs_expl:nn \l_conteq_rhs_tl \l_tmpa_tl
422     }
423   }
424   \seq_if_empty:NF \l_conteq_cells_seq {
425     \msg_warning:nn{conteq}{ignoreddata}
426   }
427   \tl_put_right:Nn #1 {#3}
428 }
429 \cs_generate_variant:Nn \conteq_print_line:Nnn {Nno}
430 \cs_generate_variant:Nn \conteq_print_line:Nnn {NVn}
431 %    \end{macrocode}
432 % \end{macro}
433
434 %
435 % \begin{environment}{conteq}
436 %
437 % The main environment of the package.
438 %    \begin{macrocode}
439 \NewEnviron{conteq}[1][\l_conteq_default_layout_tl]{
440   \tl_set:NV \l_conteq_body_tl \BODY
441   
442   \tl_if_blank:oT \l_conteq_body_tl{
443       \msg_warning:nn{conteq}{empty}
444   }
445 %    \end{macrocode}
446
447 % Figure out the layout to use\ldots
448 %    \begin{macrocode}
449   \tl_set:Nn \l_conteq_layout_tl {#1}
450 %    \end{macrocode}
451 % and set the various functions accordingly, if the layout exists.
452 %    \begin{macrocode}
453   \cs_if_exist:cTF {conteq_ \l_conteq_layout_tl _ begin:}{
454     \clist_map_inline:nn{begin:, lhs:n,rhs_only:n, rhs_expl:nn, nl:, end:}{
455       \cs_set_eq:cc {conteq_##1}{conteq_\l_conteq_layout_tl _##1}
456     }
457   }{
458     \msg_critical:nnx{conteq}{undefined layout}{\l_conteq_layout_tl}
459   }
460 %    \end{macrocode}
461
462 % Split the body into individual lines.
463 %    \begin{macrocode}
464   \seq_set_split:NnV \l_conteq_lines_seq { \\ } \l_conteq_body_tl
465
466   \tl_clear:N \l_conteq_result_tl
467 %    \end{macrocode}
468
469 % If there is only one line, simply print it.
470 %    \begin{macrocode}
471
472   \int_case:nnn {\seq_count:N \l_conteq_lines_seq}
473   {
474     {1} {
475       \tl_put_right:NV \l_conteq_result_tl \conteq_begin:
476       \tl_put_right:NV \l_conteq_result_tl \l_conteq_body_tl
477       \tl_put_right:NV \l_conteq_result_tl \conteq_end:
478     }
479   }{
480 %    \end{macrocode}
481
482 % Otherwise extract the head and the last line, and print each line using |\conteq_print_line:nn|
483 %    \begin{macrocode}
484     \seq_pop_left:NN \l_conteq_lines_seq \l_conteq_head_tl
485     \seq_pop_right:NN \l_conteq_lines_seq \l_conteq_lastline_tl
486
487     \tl_put_right:NV \l_conteq_result_tl \conteq_begin:
488     \tl_put_right:Nx \l_conteq_result_tl {
489       \conteq_args_once:NV \conteq_lhs:n \l_conteq_head_tl
490     }
491     \seq_map_inline:Nn \l_conteq_lines_seq {
492       \conteq_print_line:Nno \l_conteq_result_tl {##1} {\conteq_nl:} 
493     }
494     \conteq_print_line:NVn \l_conteq_result_tl \l_conteq_lastline_tl {} 
495     \tl_put_right:No \l_conteq_result_tl \conteq_end:
496   }
497   % Use this for debugging
498   %\tl_show:N \l_conteq_result_tl
499   \tl_use:N \l_conteq_result_tl
500 }
501 %    \end{macrocode}
502 %\end{environment}
503 %
504 %    \begin{macrocode}
505 \endinput
506 %    \end{macrocode}
507
508 %
509 % \iffalse
510 %</package>
511 % \fi
512 %
513 % \Finale
514 \endinput