1

I notice that the behaviour of environments with an optional argument that use \obeylines changes based on whether the optional argument is present or not.

I would have expected all the environments in the following example to look the same. But one is different.

What's going on? Is there something I can add to the definition of bbb to make it behave like all the others when an optional argument is present?

\documentclass{article}
\NewDocumentEnvironment{aaa}{}{\obeylines ENV:}{}
\NewDocumentEnvironment{bbb}{o}{\obeylines ENV:}{}
\NewDocumentEnvironment{ccc}{o}{ENV:}{}
\begin{document}
\begin{aaa}
  x
  y
\end{aaa}
\begin{bbb}
  x
  y
\end{bbb}
\begin{bbb}[arg]
  x
  y
\end{bbb}
\begin{ccc}\par
  x\par
  y\par
\end{ccc}
\begin{ccc}[arg]\par
  x\par
  y\par
\end{ccc}
\end{document}

Output

output

1

1 Answer 1

1

The issue is "obviously" (*) that the optional argument grabber tries to tokenize the newline token, which normally has catcode 5 ("end of line") before \obeylines is executed which changes its catcode to 13 (active).

Since it's required to tokenize the following token to determine whether or not there is an optional argument, it's unavoidable.

(in theory it's possible to use scantokens to "untokenize" it. In practice, it has a performance hit and without setting \everyeof user might hit even more perplexing bugs & maybe confusing \errorcontextlines as well)

For a workaround, set the catcode of the \endlinechar before parsing the optional argument. The cleanest way to do that at the moment (that I know of) is to define auxiliary macro/environment.

%! TEX program = lualatex

\documentclass{article}
\NewDocumentEnvironment{aaa}{}{\obeylines ENV:}{}
\NewDocumentEnvironment{innerbbb}{o}{ENV:}{}
\NewDocumentEnvironment{bbb}{}{\obeylines\innerbbb}{\endinnerbbb}
\NewDocumentEnvironment{ccc}{o}{ENV:}{}
\begin{document}
\begin{aaa}
  x
  y
\end{aaa}
\begin{bbb}
  x
  y
\end{bbb}
\begin{bbb}[arg]
  x
  y
\end{bbb}
\begin{ccc}\par
  x\par
  y\par
\end{ccc}
\begin{ccc}[arg]\par
  x\par
  y\par
\end{ccc}
\end{document}

Side note, use the plain form \innerbbb because Defining environments based on other ones: What's the right way?

Side note 2, this will make the error messages a bit confusing for runaway optional argument (i.e. you forgot to put a ]), reporting the environment name being innerbbb instead of bbb

! File ended while scanning use of \environment innerbbb .

(*) if you're sufficiently experienced in TeX programming

4
  • (originally I made the mistake that it's not necessary to tokenize the following token, fixed now)
    – user202729
    Jun 29, 2022 at 15:22
  • Actually there are "argument processors" as well, maybe there's something interesting there.
    – user202729
    Jun 29, 2022 at 15:23
  • Thinking about it, the xparse code could as well use the runtime value of @currenvir to grab the argument, but there's a small performance hit there I think.
    – user202729
    Jun 29, 2022 at 15:26
  • An alternative workaround is to add an empty mandatory argument at the end, although that makes the source code/input not as pretty..
    – user202729
    Jul 8, 2022 at 11:13

You must log in to answer this question.

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