0

My MWE using LuaLaTeX:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack} \usepackage[automark]{scrlayer-scrpage} \usepackage[english]{babel} \usepackage[babel]{microtype} \usepackage{mathtools, amssymb} \usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts \setmathfont{Latin Modern Math} \usepackage{setspace}\setdisplayskipstretch{} \usepackage{enumitem} \usepackage{xparse} \usepackage{environ} \usepackage{keyval} \usepackage{lipsum} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \adjintertext custom spacing \intertext macro (https://tex.stackexchange.com/a/280847/228055) \MHInternalSyntaxOn \newcommand{\adjintertext}[3]% #1=above skip, #2=below skip, #3=text {\ifvmode\else\@empty\fi \noalign{% %\penalty\postdisplaypenalty\vskip\belowdisplayskip \vskip-\lineskiplimit % CCS \vskip\normallineskiplimit % CCS \vskip#1 \vbox{\normalbaselines \ifdim \ifdim@totalleftmargin=\z@ \linewidth \else -\maxdimen \fi =\columnwidth \else \parshape@ne @totalleftmargin \linewidth \fi \noindent#3\par}% %\penalty\predisplaypenalty\vskip\abovedisplayskip% \vskip-\lineskiplimit % CCS \vskip\normallineskiplimit % CCS \vskip#2 }}% \MHInternalSyntaxOff %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document} \onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6] \begin{flalign} & \text{For any numbers (a)} && \tag{P'10} \ %%%%% the part related to the question %%%%% \adjintertext{0pt}{12pt}{\centering% $\begin{alignedat}{2} & \text{(i) } & a &= b, \ & \text{(ii) } & a &< b, \ & \text{(iii) } & b &< a. \end{alignedat}$% } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% & \text{For any numbers (a), (b), and (c), if (a < b) and (b < c), then (a < c).} && \tag{P'11} \ & \text{For any numbers (a), (b), and (c), if (a < b), then (a + c < b + c).} && \tag{P'12} \ & \text{For any numbers (a), (b), and (c), if (a < b) abd (0 < c), then (ac < bc).} && \tag{P'13} \end{flalign} \lipsum[2][1-8]

\end{document}

enter image description here

I wanna make a new environment myalignedat to typeset centered and aligned equations like my MWE such that instead of typing

\begin{<display math mode environment>}
    \adjintertext{0pt}{12pt}{\centering%
     \(\begin{alignedat}{2}
     & \text{(i) }   & a &= b, \\
     & \text{(ii) }  & a &< b, \\
     & \text{(iii) } & b &< a.
    \end{alignedat}\)%
}
\end{<display math mode environment>}

I would type the following instead:

\begin{<display math mode environment>}
    \begin{myalignedat}{2}[before skip=0pt, after skip=12pt]
        & \text{(i) }   & a &= b, \\
        & \text{(ii) }  & a &< b, \\
        & \text{(iii) } & b &< a.
    \end{myalignedat}
\end{<display math mode environment>}

similar to how the tcolorbox does it for its environments.

My question is: How can I define such an environment?

I've tried using \newenviron or the environ and xparse packages but to no avail since I have little knowledge about the matter. Thank you.

1 Answers1

1

Original answer

For this to work we have to somehow get the \noalign at a position where TeX finds it (inside of the \begin{myalignedat} definition seems too late for this). Therefore the following uses the env/myalignedat/before and env/myalignedat/after hooks along with some brace trick (\ifnum0=`{ and \ifnum0=`}) to get the \noalign to where we need it. Also we need to reimplement the \adjintertext code in our environment.

Once we have that out of our way the rest is pretty straight forward, we just collect an optional and a mandatory argument and use any key=val implementation that fits our needs (the following uses expkv with the expkv-def key-defining frontend1, but other packages would work as well). Another small adjustment (that one isn't really necessary though) is that the following doesn't use \begin{alignedat}...\end{alignedat} but \alignedat...\endalignedat instead.

Complete code:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack} \usepackage[automark]{scrlayer-scrpage} \usepackage[english]{babel} \usepackage[babel]{microtype} \usepackage{mathtools, amssymb} \usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts \setmathfont{Latin Modern Math} \usepackage{setspace}\setdisplayskipstretch{} \usepackage{enumitem} \usepackage{xparse} \usepackage{environ} \usepackage{lipsum} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \adjintertext custom spacing \intertext macro (https://tex.stackexchange.com/a/280847/228055) \MHInternalSyntaxOn \newcommand{\adjintertext}[3]% #1=above skip, #2=below skip, #3=text {\ifvmode\else\@empty\fi \noalign{% %\penalty\postdisplaypenalty\vskip\belowdisplayskip \vskip-\lineskiplimit % CCS \vskip\normallineskiplimit % CCS \vskip#1 \vbox{\normalbaselines \ifdim \ifdim@totalleftmargin=\z@ \linewidth \else -\maxdimen \fi =\columnwidth \else \parshape@ne @totalleftmargin \linewidth \fi \noindent#3\par}% %\penalty\predisplaypenalty\vskip\abovedisplayskip% \vskip-\lineskiplimit % CCS \vskip\normallineskiplimit % CCS \vskip#2 }}% \MHInternalSyntaxOff \makeatletter \usepackage{expkv-def} \ekvdefinekeys{myalignedat} { skip before skip = \myalignedat@before ,skip after skip = \myalignedat@after } \AddToHook{env/myalignedat/before} {\ifvmode\else\@empty\fi\noalign{\ifnum0=}\fi} \AddToHook{env/myalignedat/after} {\ifnum0={\fi}} \MHInternalSyntaxOn \newenvironment{myalignedat}[2][] {% \ekvset{myalignedat}{#1}% \vskip\myalignedat@before \vbox\bgroup\normalbaselines \ifdim \ifdim@totalleftmargin=\z@ \linewidth \else -\maxdimen \fi =\columnwidth \else \parshap@ne@totalleftmargin \linewidth \fi \noindent \centering(\alignedat{#2}% } {% \endalignedat)% \par\egroup \vskip-\lineskiplimit \vskip\normallineskiplimit \vskip\myalignedat@after } \MHInternalSyntaxOff \makeatother %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{document} \onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6] \begin{flalign} & \text{For any numbers (a)} && \tag{P'10} \ %%%%% the part related to the question %%%%% \begin{myalignedat}[before skip=0pt, after skip=12pt]{2} & \text{(i) } & a &= b, \ & \text{(ii) } & a &< b, \ & \text{(iii) } & b &< a. \end{myalignedat} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% & \text{For any numbers (a), (b), and (c), if (a < b) and (b < c), then (a < c).} && \tag{P'11} \ & \text{For any numbers (a), (b), and (c), if (a < b), then (a + c < b + c).} && \tag{P'12} \ & \text{For any numbers (a), (b), and (c), if (a < b) abd (0 < c), then (ac < bc).} && \tag{P'13} \end{flalign} \lipsum[2][1-8]

\end{document}

Output:

enter image description here

1Disclaimer: I'm the package author of expkv and friends


Improved version needing to hack \begin

The above code version couldn't detect whether a \\ was used before it or not, and thus lead to inconsistent vertical spacing. The following fixes that by patching LaTeX's \begin to have another hook. The patch should be fine and not affect any other usage of \begin.

\documentclass[oneside,DIV=12]{scrbook}

\makeatletter % redefine \begin to have another hook. This hook is no generic hook, so we % have to use \NewHook{env/#1/evenbeforebefore} before we can use \AddToHook % on it (for each environment that needs it) \edef\begin#1% {% \unexpanded {% \ifx\protect\relax \else \expandafter@gobbletwo \fi }% \noexpand\UseHook{env/#1/evenbeforebefore}% \noexpand\protect\expandafter\noexpand\csname begin \endcsname{#1}% } \makeatother

\usepackage{scrhack} \usepackage[automark]{scrlayer-scrpage} \usepackage[english]{babel} \usepackage[babel]{microtype} \usepackage{mathtools, amssymb} \usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts \setmathfont{Latin Modern Math} \usepackage{setspace}\setdisplayskipstretch{} \usepackage{lipsum} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\makeatletter \usepackage{expkv-def} \ekvdefinekeys{myalignedat} { skip before skip = \myalignedat@before ,skip after skip = \myalignedat@after } \NewHook{env/myalignedat/evenbeforebefore} \AddToHook{env/myalignedat/evenbeforebefore} {\ifvmode\else\@empty\fi\noalign{\ifnum0=}\fi} \AddToHook{env/myalignedat/after} {\ifnum0={\fi}} \MHInternalSyntaxOn \newenvironment{myalignedat}[2][] {% \ekvset{myalignedat}{#1}% \vskip\myalignedat@before \vbox\bgroup\normalbaselines \ifdim \ifdim@totalleftmargin=\z@ \linewidth \else -\maxdimen \fi =\columnwidth \else \parshap@ne@totalleftmargin \linewidth \fi \noindent \centering(\alignedat{#2}% } {% \endalignedat)% \par\egroup \vskip-\lineskiplimit \vskip\normallineskiplimit \vskip\myalignedat@after } \MHInternalSyntaxOff \makeatother %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document} \onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6] \begin{flalign} & \text{For any numbers (a) with much text following it} && \tag{P'10} \ %%%%% the part related to the question %%%%% \begin{myalignedat}[before skip=0pt, after skip=0pt]{2} & \text{(i) } & a &= b, \ & \text{(ii) } & a &< b, \ & \text{(iii) } & b &< a. \end{myalignedat} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% & \text{For any numbers (a), (b), and (c), if (a < b) and (b < c), then (a < c).} && \tag{P'11} \ & \text{For any numbers (a), (b), and (c), if (a < b), then (a + c < b + c).} && \tag{P'12} \ & \text{For any numbers (a), (b), and (c), if (a < b) abd (0 < c), then (ac < bc).} && \tag{P'13} \end{flalign} \lipsum[2][1-8]

\end{document}


Pseudo-environment version

This version uses a fully expandable macro to start a pseudo-environment. It doesn't require any hacking of standard LaTeX macros, but it still uses the brace hacks. It expands to \noalign directly and can then use unexpandable argument grabbing and key=value parsing.

The environment is started by \beginmyalignedat[<key=value>]{<alignedat-arg>} and ended by \stopmyalignedat.

Complete code:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack} \usepackage[automark]{scrlayer-scrpage} \usepackage[english]{babel} \usepackage[babel]{microtype} \usepackage{mathtools, amssymb} \usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts \setmathfont{Latin Modern Math} \usepackage{setspace}\setdisplayskipstretch{} \usepackage{enumitem} \usepackage{xparse} \usepackage{environ} \usepackage{keyval} \usepackage{lipsum}

\usepackage{expkv-def}

\makeatletter \ekvdefinekeys{myalignedat} { skip before skip = \myalignedat@before ,skip after skip = \myalignedat@after } \MHInternalSyntaxOn \newcommand*\beginmyalignedat {% \ifvmode\else\@empty\fi \noalign{\ifnum0=}\fi \myalignedat@ } \newcommand\myalignedat@[2][] {% \ekvset{myalignedat}{#1}% \vskip-\lineskiplimit \vskip\normallineskiplimit \vskip\myalignedat@before \vbox\bgroup \normalbaselines \ifdim \ifdim\@totalleftmargin=\z@ \linewidth \else -\maxdimen \fi =\columnwidth \else \parshape\@ne\@totalleftmargin\linewidth \fi \noindent \centering $\begin{alignedat}{#2}% } \newcommand\stopmyalignedat {% \end{alignedat}$% \par \vskip-\lineskiplimit \vskip\normallineskiplimit \vskip\myalignedat@after \egroup \ifnum0={\fi}% } \MHInternalSyntaxOff \makeatother

\begin{document} \onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6] \begin{flalign} & \text{For any numbers (a)} && \tag{P'10} \ %%%%% the part related to the question %%%%% \beginmyalignedat[after skip=12pt]{2} & \text{(i) } & a &= b, \ & \text{(ii) } & a &< b, \ & \text{(iii) } & b &< a. \stopmyalignedat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% & \text{For any numbers (a), (b), and (c), if (a < b) and (b < c), then (a < c).} && \tag{P'11} \ & \text{For any numbers (a), (b), and (c), if (a < b), then (a + c < b + c).} && \tag{P'12} \ & \text{For any numbers (a), (b), and (c), if (a < b) abd (0 < c), then (ac < bc).} && \tag{P'13} \end{flalign} \lipsum[2][1-8]

\end{document}


Normal macro version

A macro variant that just grabs the arguments in an expandable way, uses an expandable key=value interface, and hence "directly" expands to \adjintertext, such that it behaves as if \adjintertext was used like in your code. An alternative version could use the same brace trick like the other solutions to use non-expandable argument grabbing and key=value solutions.

The syntax is:

\myalignedat[<key=val>]{<alignedat-arg>}{<alignedat-content>}

Complete code:

\documentclass[oneside,DIV=12]{scrbook}

\usepackage{scrhack} \usepackage[automark]{scrlayer-scrpage} \usepackage[english]{babel} \usepackage[babel]{microtype} \usepackage{mathtools, amssymb} \usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math} % Math fonts \setmathfont{Latin Modern Math} \usepackage{setspace}\setdisplayskipstretch{} \usepackage{enumitem} \usepackage{xparse} \usepackage{environ} \usepackage{keyval} \usepackage{lipsum} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \adjintertext custom spacing \intertext macro (https://tex.stackexchange.com/a/280847/228055) \MHInternalSyntaxOn \newcommand{\adjintertext}[3]% #1=above skip, #2=below skip, #3=text {\ifvmode\else\@empty\fi \noalign{% %\penalty\postdisplaypenalty\vskip\belowdisplayskip \vskip-\lineskiplimit % CCS \vskip\normallineskiplimit % CCS \vskip#1 \vbox{\normalbaselines \ifdim \ifdim@totalleftmargin=\z@ \linewidth \else -\maxdimen \fi =\columnwidth \else \parshape@ne @totalleftmargin \linewidth \fi \noindent#3\par}% %\penalty\predisplaypenalty\vskip\abovedisplayskip% \vskip-\lineskiplimit % CCS \vskip\normallineskiplimit % CCS \vskip#2 }}% \MHInternalSyntaxOff %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\usepackage{expkv-cs}

% grabbing an optional argument expandable \NewExpandableDocumentCommand\myalignedat{O{} m m} {% % forward all arguments to \myalignedatKV \myalignedatKV{#1}{#2}{#3}% } % splitting the first argument into two arguments based on a key=value interface \ekvcSplitAndForward\myalignedatKV\myalignedatDO { before skip=0pt ,after skip=0pt } % grabbing all the arguments and setting the output \newcommand\myalignedatDO[4] {% \adjintertext{#1}{#2} {% \centering $% \begin{alignedat}{#3} #4% \end{alignedat}% $% }% }

\begin{document} \onehalfspacing\KOMAoptions{DIV=current}

\lipsum[1][1-6] \begin{flalign} & \text{For any numbers (a)} && \tag{P'10} \ %%%%% the part related to the question %%%%% \myalignedat[after skip=12pt]{2} { & \text{(i) } & a &= b, \ & \text{(ii) } & a &< b, \ & \text{(iii) } & b &< a. } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% & \text{For any numbers (a), (b), and (c), if (a < b) and (b < c), then (a < c).} && \tag{P'11} \ & \text{For any numbers (a), (b), and (c), if (a < b), then (a + c < b + c).} && \tag{P'12} \ & \text{For any numbers (a), (b), and (c), if (a < b) abd (0 < c), then (ac < bc).} && \tag{P'13} \end{flalign} \lipsum[2][1-8]

\end{document}

Skillmon
  • 60,462
  • Thanks for answering! Just one little thing though, compared to my MWE, it seems that there's some extra vertical space even when before skip=0pt. Is there a way to have the preceding vertical spacing similar to my example? – Farrel Ahmed May 23 '22 at 12:50
  • @FarrelAhmed I think that the \ifvmode\else\\\@empty\fi doesn't work correctly. If you omit the \\ before \begin{myalignedat} the spacing should be correct. I'm not yet sure what's causing this. – Skillmon May 23 '22 at 13:58
  • Ah I see, if possible I really want the preceding and succeeding vertical space to be at least roughly if not exactly equivalent when before skip=0pt and after skip=0pt – Farrel Ahmed May 23 '22 at 14:22
  • @FarrelAhmed as long as you don't want to switch to a macro, I'm afraid there isn't much I can do about the space inconsistency. Either don't ever use \\ before the environment (it'll do so itself) or don't use an environment. The problem is that even the env/myalignedat/before hook is only executed after a new align-row was started (\begin is defined using the \protect mechanism), hence there is nothing I can do about this. If on the other hand a macro grabbing those arguments would be fine (so e.g. instead of \begin{myalignedat} using \beginmyalignedat) I could probably fix this – Skillmon May 23 '22 at 16:02
  • @FarrelAhmed the alternative would be changing the definition of \begin (I'm relatively sure that it is safe, but not sure whether it's a good idea). – Skillmon May 23 '22 at 18:34
  • If you don't mind, do you think you can temporary change the definition of \begin then redefine it to be the default after? Or is that still not the best idea? (I can accept your answer already if you want, though) – Farrel Ahmed May 24 '22 at 01:19
  • @FarrelAhmed a temporary redefinition wouldn't solve the issue as that can't be done expandably and hence doesn't solve our issue at hand. I can post the code with the redefinition of \begin though (it should be safe). – Skillmon May 24 '22 at 05:23
  • Hello, I'm sorry but I could not compile my document using the new code as it gives a lot of errors. – Farrel Ahmed May 24 '22 at 12:45
  • @FarrelAhmed is your TeX Live installation up to date? Which kind of errors? Please note that I only test my answers against the most recent TeX Live (2022 in this case) and I update that at least weekly. If the above doesn't work you should switch from an environment to a command (or a command-version of an environment with a \beginmyalignedat ...\stopmyalignedat pair -- names not fixed). If you want I could provide both (but I might need some time to find time doing that) – Skillmon May 25 '22 at 06:43
  • @FarrelAhmed and forget about my comment directly above. I made a small change (that I didn't test) that broke stuff. The version patching \begin should work now. – Skillmon May 25 '22 at 16:40
  • I'm compiling on Overleaf which I do believe should use the latest TeX Live distribution – Farrel Ahmed May 26 '22 at 14:08
  • If you don't mind, yes please, could you provide that? I'm willing to wait, because right now my best personal solution is to just use a code snippet shortcut for \adjintertext{<before skip>}{<after skip>}{\centering\(\begin{alignedat}{<num>} <aligned math> \end{alignedat}\)} when I'm using a Text Editor like VS Code which I don't mind though I'm still looking to see if I can define a new environment as per my question. Thanks in advance and for everything so far! – Farrel Ahmed May 26 '22 at 14:37
  • @FarrelAhmed I already provided those other versions 22h ago :P There is my "original answer", the "improved version" (which hacks \begin), the "pseudo-environment" version (that's the one using \beginmyalignedat and \stopmyalignedat), and a "macro version" (that's the one using normal arguments). (my answer now has 4 sections with the respective solution) – Skillmon May 26 '22 at 15:13