# Equivalent for \bgroup \egroup in LaTeX3

I am trying to apply a expl3 function to the contents of an environment. In LaTeX2e this can be achieved by using \bgroup and \egroup. In expl3, something does not work.

I would expect the following code to print "AAA hey BBB". Instead, it prints "AAA BBB hey".

\ExplSyntaxOn

\cs_new:Npn \bar:n #1 {
AAA #1 BBB
}

\NewDocumentEnvironment{foo}{}{
\bar:n \bgroup
}{
\egroup
}

\ExplSyntaxOff

\begin{document}

\begin{foo}
hey
\end{foo}

\end{document}


Any thoughts on why this happens and possible workarounds?

## Edit

This is my current approach:

\cs_new:Npn \env_new:Nn #1#2 {
\tl_new:N #1
\tl_set:Nn #1 { #2 }
}

\cs_new:Npn \env_begin:N #1 {}
\cs_new:Npn \env_end:N #1 {}

\cs_new:Npn \env_capture_on: {
\global \let \env_begin:N \group_begin:
\global \let \env_end:N   \group_end:
}

\cs_new:Npn \env_capture_off: {
\global\let\env_begin:N\env_original_begin:N
\global\let\env_end:N\env_original_end:N
}

\cs_new:Npn \env_original_begin:N #1 {
\env_capture_on:
\tl_use:N #1
\group_begin:
\env_capture_off:
}

\cs_new:Npn \env_original_end:N #1 {
}

\env_capture_off:

\cs_new:Npn \foo:n #1 {
AAA #1 BBB
}

\env_new:Nn \baf {
\foo:n
}

\env_begin:N \baf
hey
\env_end:N \baf


This won't work, since \group_begin: and \group_end: cannot be used to capture function arguments (i.e. \foo \group_begin: A \group_end: works differently than \foo { A }).

Is there any way a control sequence can be temporally forced to behave as if it was an explicit brace?

## A solution

I think I have a solution. As I mentioned in the comments, one could combine pattern matching with counting the number of \begins to capture the contents of an environment. It was a bit suprising to me that this is precisely what is going on in environ, just below a LOT of notation.

Since I know that environ failed in my intended application, I decided to reimplement it in the simplest possible way, so that I can figure out where does my code fail (now I have an idea about what went wrong, but that's not the point). Below you can find an implementation in expl3. I have not tested it thoroughly, but I believe it works.

Any comments or reviews are hugely appreciated.

\int_new:N \env_count
\cs_new:Npn \env_new:Nn #1#2 {
\cs_new:cpn { env_defined@ \cs_to_str:N #1 :nn } ##1##2 {
#2
}
}

\cs_new:Npn \env_countbegin:w #1\xbegin#2 {
\cs_if_free:NTF #2 {
\int_incr:N \env_count
\env_countbegin:w
} {
\cs_if_eq:NNTF #2 \xend {} {
\int_incr:N \env_count
\env_countbegin:w
}
}
}

\cs_new:Npn \env_collect:w #1#2#3#4\xend#5 {
\env_countbegin:w #4\xbegin\xend
\int_compare:nTF { \env_count = 0 } {
\use:c { env_defined@ \cs_to_str:N #1 :nn } { #3 #4 } { #2 }
}{
\int_decr:N \env_count
\env_collect:w {#1} {#2} { #3 #4 \xend{#5} }
}
}

\NewDocumentCommand \xbegin {mo} {
\int_zero:N \env_count
\env_collect:w {#1} {#2} {}
}

\NewDocumentCommand \xend {} {}

\env_new:Nn \foo {
AAA #1 BBB
}

\xbegin{\foo}
\xbegin{\foo}
hey
\xend{\foo}
\xend{\foo}

• You want to capture the whole content of the the environment, I understood that. I don't think that \begingroup and \endgroup is the correct way – user31729 Apr 21 '17 at 14:43
• @ChristianHupfer \group_begin: is the equivalent of \begingroup and not of \bgroup. \begingroup is the primitive while \bgroup has been let to {. The equivalent in expl3 is \c_group_begin_token. – cgnieder Apr 21 '17 at 15:52
• @ChristianHupfer I know. You can't generally exchange { for \bgroup. It works in some cases (like boxes) but not for macros. \def\bar#1{AAA#1BBB} \newenvironment{foo}{\bar\bgroup}{\egroup} would fail the same way… expl3 is no different – cgnieder Apr 21 '17 at 16:01
• As regards to your question in the edit, the answer is no: only explicit characters of category code 1 and 2 can be used for grabbing a token list as an undelimited macro argument. – egreg Apr 22 '17 at 14:03
• If you have a self-answer, please post it separately not as an edit to the question – Joseph Wright Apr 22 '17 at 22:00

It has never been possible to grab an argument with \bgroup and \egroup. The version

\newenvironment{foo}{%
\baz\bgroup
}{%
\egroup
}
\newcommand{\baz}[1]{AAA #1 BBB}


would fail in exactly the same way. The argument to \baz would be \bgroup, so the output of

x\begin{foo}
key
\end{foo}y


would be

xAAA<space><space>BBB<space>key<space>y


One of the unexpected spaces comes from the end-of-line after \begin{foo}, the other one from the end-of-line after key.

It is possible to use environ, as shown by Christian Hupfer:

\usepackage{xparse,environ}

\ExplSyntaxOn
\NewEnviron{foo}
{
\jaeya_baz:V \BODY
}

\cs_new:Nn \jaeya_baz:n { AAA~#1~BBB }
\cs_generate_variant:Nn \jaeya_baz:n { V }
\ExplSyntaxOff


and the output of the code above would be the expected

xAAA<space>key<space}BBBy


Adding features similar to \NewEnviron in xparse should be on the to-do list for the LaTeX team.

• I second this: "Adding features similar to \NewEnviron in xparse should be on the to-do list for the LaTeX team." – Jonathan Komar Oct 20 '17 at 13:00
• @JonathanKomar Now there is! The code can be changed into \NewDocumentEnvironment{foo}{b}{\jaeya_baz:n{#1}}{} – egreg Mar 8 '19 at 13:03
• Awesome!!! xparse will become a standard package in my repetoire, I think. – Jonathan Komar Mar 8 '19 at 13:13

This is a way with environ and \NewEnviron, catching \BODY and applying it within a wrapper environment, defined with xparse's \NewDocumentEnvironment, which means that all features from xparse - argument specifiers can be used still.

\documentclass{article}
\usepackage{environ}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Nn \bar:n {
AAA #1 BBB
}

\NewEnviron{foointernal}{
\bar:n {\BODY}
}

\ExplSyntaxOff

\let\origfoointernal\foointernal
\let\origendfoointernal\endfoointernal

\NewDocumentEnvironment{foo}{}{%
\origfoointernal%
}{%
\origendfoointernal%
}

\begin{document}

\begin{foo}
hey
\end{foo}

\begin{foo}
\blindtext

Hello World
\end{foo}

\end{document}


• Thanks for your reply. Although in this case it would work, I am afraid the use case is way more complex, and environ was problematic in a previous version (frankly, I don't remember how exactly). – Jaeya Apr 21 '17 at 14:44
• As I said, environ was very problematic in the past for my code, to the extent that I already had to migrate everything to the \bgroup / \egroup style due to my inability to make it work. I would just like to use something similar with LaTeX3 – Jaeya Apr 21 '17 at 15:07
• @Jaeya: I don't know what the problem was with your then... I showed you a working solution, based on the document you gave in your post – user31729 Apr 21 '17 at 15:19
• And a very appreciated one! I do understand that it is not easy to provide a more suitable solution without more information that, unfortunately, I do not have. – Jaeya Apr 21 '17 at 15:23
• I guess the % at the end of the lines between \ExplSyntaxOn and ...Off are due to habit? :) – cgnieder Apr 21 '17 at 15:54

You know you want to use \bar:n in an environment to grab the contents. So just make it scan ahead for \end and insert \end again at the end of the replacement text.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\cs_new:Npn \bar:n #1 \end {
AAA #1 BBB \end
}

\NewDocumentEnvironment{foo}{}{\bar:n}{}

\ExplSyntaxOff

\begin{document}

\begin{foo}
hey
\end{foo}

\end{document}


• Will this work for nested environments as well? (E.g. \begin{foo} \begin{foobar} Hey \end{foobar}\end{foo}} The idea is thrilling, but I think the nesting is exactly the problem what makes the environ code 'hard' – user31729 Apr 21 '17 at 21:59
• I already thought of this - I was using a quark for pattern matching, though. As @ChristianHupfer mentioned, the problem here is nesting, but I think there is a workaround - essentially, counting nesting levels. I know, it's ugly. – Jaeya Apr 22 '17 at 3:52

I frankly don't know if it will work once the whole package is rewritten, but at least now I can understand what is going on. There are a few limitations: defined environments have only two parameters. #1 represents the contents of the environment; #2 represents a square-bracket parameter, which in principle can be used to contain key-values and so overcome this limitation.

Furthermore, my environments work with commands \xbegin{\foo} and \xend{\foo}. The underlying structure of these commands is different from that of LaTeX environments, so I decided to use different keywords. Anyway, I guess that the approach could be extended to apply to LaTeX environments.

Any review or comments on the code are hugely welcome and appreciated!

\documentclass[10pt]{article}
\usepackage{expl3}

\ExplSyntaxOn

\int_new:N \env_count
\cs_new:Npn \env_new:Nn #1#2 {
\cs_new:cpn { env_defined@ \cs_to_str:N #1 :nn } ##1##2 {
#2
}
}

\cs_new:Npn \env_countbegin:w #1\xbegin#2 {
\cs_if_free:NTF #2 {
\int_incr:N \env_count
\env_countbegin:w
} {
\cs_if_eq:NNTF #2 \xend {} {
\int_incr:N \env_count
\env_countbegin:w
}
}
}

\cs_new:Npn \env_collect:w #1#2#3#4\xend#5 {
\env_countbegin:w #4\xbegin\xend
\int_compare:nTF { \env_count = 0 } {
\use:c { env_defined@ \cs_to_str:N #1 :nn } { #3 #4 } { #2 }
}{
\int_decr:N \env_count
\env_collect:w {#1} {#2} { #3 #4 \xend{#5} }
}
}

\NewDocumentCommand \xbegin {mo} {
\int_zero:N \env_count
\env_collect:w {#1} {#2} {}
}

\NewDocumentCommand \xend {} {}

\env_new:Nn \foo {
AAA #1 BBB
}

\ExplSyntaxOff

\begin{document}

\xbegin{\foo}
\xbegin{\foo}
hey
\xend{\foo}
\xend{\foo}

\end{document}