0

I am posting this as a general question prior to introducing the specific use case. Apologies if this has already been posted and I am using the incorrect terms for what I want, my searches have been relatively fruitless.

General Case

I want to create a generic environment template that is passed commands from inside the environment. These commands then define how the environment renders on compile. I want to do this so the number of optional commands I pass to the environment is arbitrary for formatting purposes. Additionally, I want to add a large number of optional commands while avoiding a giant string of {}{}{}{}.

Here is a non-working example of what I want:

\documentclass{article}

\newenvironment{testenv}%
    {%
        This is \Alice\Bob
        \begin{center}
        I want to talk about \Bob
    }%
    {%
        \end{center}
    }%

\newcommand{\Alice}[1]{#1}
\newcommand{\Bob}[1]{#1}

\begin{document}
    \begin{testenv}
        \Alice{asdf}
        \Bob{jkl}
        this is everything
    \end{testenv}
    
    \begin{testenv}
        \Bob{jkl}
        this is just Bob
    \end{testenv}
\end{document}

In this example, the custom environment always prints "I want to talk about \Bob" along with additional text. However, the header for the verbatim environment is dependent on what, if anything, we put in \Alice and \Bob.

Relevant Posts

The Ask

  • Obviously this doesn't work. Am I completely off base when thinking about the relationship between commands and environments in TeX?
  • Is there a way to make this general example work?
  • Is this a case for xparse? I have never used it, so how would I do this?

Specific Case

What I really want to do is create a custom recipe environment with relevant information in the margins (this is a niche case, so I figured I would pose the general question first). For this, I am using the marginnote package. There is a lot of information I want to have available to the margin, and I want to do it with variables for ease of replication. Currently, I have individual commands for different elements I want in the box. From my style template (This is not a MWE):

\newcommand{\serves}[1]{%
    \marginnote{Serves: #1~\\*}%
}
\newcommand{\vegetarian}{%
    \marginnote{\textcolor{forestgreen}{\textbf{Veggie}}}~\\*%
}
\newcommand{\vegan}{%
    \marginnote{\colorbox{green!20}{\textbf{Vegan}}}~\\*%
}
\newcommand{\preptime}[1]{%
    \marginnote{Prep: #1}~\\*%
}
\newcommand{\cooktime}[1]{%
    \marginnote{Cook time: #1}~\\*%
}

Individual recipes require specific combinations of these, often multiple. You will notice the hacky ~\\* at the end of each command. If I do not include this, the boxes overlap each other. If I do include it, the line breaks also persist in the document. See example image:

A comparison of my example template with and without the ~\\*

I am converting my hacky solution to a cleaner template that avoids the overlap problem in my ``newenvironment{recipe}, but I am yet to find a way to do this programatically in the margins with all of the optional arguments that I want.

The Ask

  • If there is a specific tool I should use to achieve the goals for my specific case, please feel free to comment on it and/or include it in an answer to the general case. However, please prefer answering the general question.
8
  • you used verbatim in your first example which completely changes the question as nesting verbatim only possible in very limited ways. it is hard to imgine you need verbatim for a recipe book though, you are not cooking tex source code??? Dec 20, 2022 at 19:47
  • your example doesn't print anything. It errors as you can't hide verbatim like this inside another environment. Dec 20, 2022 at 19:47
  • ~\\ is a very weird construct, probably just use \par Dec 20, 2022 at 19:48
  • @DavidCarlisle Ha, its not a coding cookbook! If I wrote that, it would be nothing but a recipe for disaster! I just grabbed verbatim as it was the first default environment that came to mind. I should fix that so it un-breaks the curly braces.
    – WesH
    Dec 20, 2022 at 19:52
  • you should decide first if verbatim is a requirement. It would require different definition forms and limit the ways it can be used. Dec 20, 2022 at 19:56

1 Answer 1

4

It really is not very clear what input forms you want or what output they should generate, but here is an environment that takes one optional argument which is a comma separated list of key/value pairs.

enter image description here

\documentclass{article}


\ExplSyntaxOn

\bool_new:N\l_bool_alice
\bool_new:N\l_bool_bob
\keys_define:nn{abc}{
alice.bool_set:N =\l_bool_alice,
bob.bool_set:N = \l_bool_bob,
vegan.tl_set:N= \l_vegan_tl
}
\NewDocumentEnvironment{testenv}{O{}}
    {
   \keys_set:nn {abc}{#1}
        \begin{center}
        \bool_if:NT\l_bool_alice {I ~want ~to ~talk ~about ~Alice.}\par
        \bool_if:NT\l_bool_bob {I ~want ~to ~talk ~about ~Bob.}\par
    }
    {
        \tl_if_empty:NF\l_vegan_tl{\marginpar{\bfseries\l_vegan_tl}}
        \end{center}
    }
\ExplSyntaxOff

\begin{document}
    
\begin{testenv}[alice]
  aaa
\end{testenv}

\bigskip\hrule\bigskip

\begin{testenv}[alice,bob,vegan=wibble]
  bbb
\end{testenv}
\end{document}
6
  • Thanks for the excellent starting point, David. This is my first time diving into expl3, so I'm going to take things slow and experiment a bit until I figure it out. A few clarifying questions: 1) \keys_define:nn{abc} and friends appear to call a module called abc if I'm reading the right docs, but this is not the abc music package, correct? 2) In \bool_if:NT\l_bool_alice {I ~want ~to ~talk ~about ~Alice.}\par is the spacing deliberate to fit with the \ExplSyntaxOn?
    – WesH
    Dec 21, 2022 at 3:22
  • I could have used the classic keyval package (as used by \incudegraphics) (very reliable author) but as there are literally millions of examples of that on the web, I used the modern way that is built in to recent formats. Yes white space is ignored in \ExplSyntaxOn so ~ makes a space (a real space, not a non-breaking space as ~ makes in the main document) abc is just a random string here, WesH might have been a better string for the context @WesH Dec 21, 2022 at 9:39
  • udefined or undefined? It compiles the same either way, but I've never seen udefined.
    – WesH
    Dec 21, 2022 at 19:34
  • This works better when I replace \udefined with \empty. While in your example, the lack of vegan=wibble does not show up in the first, a placeholder still exists in the document. You can confirm this by replacing the definition conditional with: \ifx\l_vegan_tl\udefined\else\marginpar{test=\bfseries\l_vegan_tl}\fi
    – WesH
    Dec 21, 2022 at 19:37
  • @WesH it was a typo but there is no signifcance to either name but as you say, it should be \empty or better use \tl_if_empty:NF rather than \ifx (I'll fix) Dec 21, 2022 at 20:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .