The eqn environment
Convenient maths environment
The following code defines the eqn environment,
a maths environment with some convenience functions:
%%
%% Math environments
%%
\ExplSyntaxOn
\cs_generate_variant:Nn \seq_set_split:Nnn { NnV }
\tl_new:N \l_content_tl
\tl_new:N \l_last_tl
\tl_new:N \l_eqn_type
\usepackage{mleftright}
\NewDocumentEnvironment{eqn}{ob}{
\tl_set:Nn \l_tmpa_tl {#2}
\tl_trim_spaces:N \l_tmpa_tl
\tl_set:Nx \l_last_tl { \tl_range:Nnn { \l_tmpa_tl } { -1 } { -1 } }
\tl_if_in:nVTF {.,} \l_last_tl {
\tl_set:Nx \l_content_tl { \tl_range:Nnn { \l_tmpa_tl } { 1 } { -2 } }
} {
\tl_set:NV \l_content_tl { \l_tmpa_tl }
\tl_set:Nn \l_last_tl {}
}
\tl_set:Nn \l_eqn_type {d}
\keys_define:nn { benno/argument } {
inline .value_forbidden:n = true,
inline .code:n = {\tl_set:Nn \l_eqn_type {i}},
i .value_forbidden:n = true,
i .code:n = {\tl_set:Nn \l_eqn_type {i}},
align .value_forbidden:n = true,
align .code:n = {\tl_set:Nn \l_eqn_type {a}},
a .value_forbidden:n = true,
a .code:n = {\tl_set:Nn \l_eqn_type {a}},
display .value_forbidden:n = true,
display .code:n = {\tl_set:Nn \l_eqn_type {d}},
d .value_forbidden:n = true,
d .code:n = {\tl_set:Nn \l_eqn_type {d}},
oneline .value_forbidden:n = true,
oneline .code:n = {\tl_remove_all:Nn \l_content_tl {&}
\tl_remove_all:Nn \l_content_tl {\\}},
autosize .value_forbidden:n = true,
autosize .code:n = {
\tl_replace_all:Nnn \l_content_tl {\lvert}{\mleft\lvert}
\tl_replace_all:Nnn \l_content_tl {\rvert}{\mright\rvert}
\tl_replace_all:Nnn \l_content_tl {\lVert}{\mleft\lVert}
\tl_replace_all:Nnn \l_content_tl {\rVert}{\mright\rVert}
\tl_replace_all:Nnn \l_content_tl {\langle}{\mleft\langle}
\tl_replace_all:Nnn \l_content_tl {\rangle}{\mright\rangle}
\tl_replace_all:Nnn \l_content_tl {(|}{\mleft\lvert}
\tl_replace_all:Nnn \l_content_tl {|)}{\mright\rvert}
\tl_replace_all:Nnn \l_content_tl {(||}{\mleft\lVert}
\tl_replace_all:Nnn \l_content_tl {||)}{\mright\rVert}
\tl_replace_all:Nnn \l_content_tl {(<}{\mleft\langle}
\tl_replace_all:Nnn \l_content_tl {>)}{\mright\rangle}
\tl_replace_all:Nnn \l_content_tl {(}{\mleft(}
\tl_replace_all:Nnn \l_content_tl {)}{\mright)}
\tl_replace_all:Nnn \l_content_tl {[}{\mleft[}
\tl_replace_all:Nnn \l_content_tl {]}{\mright]}
\tl_replace_all:Nnn \l_content_tl {\{}{\mleft\{}
\tl_replace_all:Nnn \l_content_tl {\}}{\mright\}}
\tl_replace_all:Nnn \l_content_tl {\lceil}{\mleft\lceil}
\tl_replace_all:Nnn \l_content_tl {\rceil}{\mright\rceil}
\tl_replace_all:Nnn \l_content_tl {\lfloor}{\mleft\lfloor}
\tl_replace_all:Nnn \l_content_tl {\rfloor}{\mright\rfloor}
},
}
\IfValueT{#1}{
\keys_set:nn { benno/argument } {#1}
}
\tl_log:N \l_content_tl
\str_case:Vn \l_eqn_type {
{i} {
\math
\l_content_tl
}
{a} {
\equation
\aligned
\l_content_tl
}
{d} {
\equation
\l_content_tl
}
}
} {
\str_case:Vn \l_eqn_type {
{i} {
\tl_if_eq:NnTF \l_last_tl {.} {
\endmath \ifnocf{.}
} {
\l_last_tl\endmath
}
}
{a} {
\endaligned
\endequation
}
{d} {
\tl_if_eq:NnTF \l_last_tl {.} {
\ifnocf{.}\endequation
} {
\l_last_tl\endequation
}
}
}
}
\ExplSyntaxOffeqn environment has the following convenience functions:
Switching between inline, displayed, and aligned maths
i, d, or o in the optional argument, the environment will
produce inline maths (like $...$), a displayed equation (like \begin{equation} ... \end{equation}),
or an aligned equation (like \begin{equation}\begin{aligned} ... \end{aligned}\end{equation}),
respectively. No optional argument defaults to displayed maths.Special treatment of punctuation
. or ,) it will be
treated specially. If the i is present as an optional argument, the punctuation
will be moved outside of the maths environment. Furthermore, a . will only be output
if there are no definitions to load (because it is assumed that every sentence will be followed by a
\cfload or \cfout).Ignoring aligment
oneline in the optional argument (as in \begin{eqn}[d,oneline] ... \end{eqn})
has the effect that all \\ and & in the equation will be ignored.
This is useful for quickly switching an aligned equation to a displayed or inline equation.
Note that this ignores all \\ and &, so it will not work well
if the equation contains, e.g., a matrix.Autosizing delimiters
Using autosize in the optional argument autosizes all paired delimiters in the equation,
e.g., all (...) will be treated like \mleft(...\mright) (it works for
(...), [...], \{...\}, \lvert...\rvert,
\lVert...\rVert, \langle...\rangle,
\lceil...\rceil, and \lfloor...\rfloor).
This can be useful if you want to quickly write down an equation without worrying about the size of delimiters and have it look decent. It's probably not a good idea to use this in a final document, though. See the tips section on delimiters on how to do this properly.
[You can actually write (|...|), (||...||), and (<...>)
in place of \lvert...\rvert, \lVert...\rVert, and \langle...\rangle, respectively,
but again, while this might be useful for writing something out quickly, it's not really meant
for production use.]