I take this question as an exercise in playing with category codes and macro expansion.
But honestly, I don't see much point in writing
\begin{mynewenv}{EnvironmentWhichIActuallyWant}<Arguments>
instead of directly writing
\begin{EnvironmentWhichIActuallyWant}<Arguments>
.
Be that as it may.
You attempt to have an environment "mynewenv" carry out another environment which is called "math".
A problem with this is:
"mynewenv" starts "math". Then in the .tex-input the \end{...}
-command for "mynewenv" is encountered which in turn does the \end{...}
-command for "math".
This way the order in which ending-commands for "math" and "mynewenv" are found, and thus the order in which underlying ending-commands of these environments and hooks at the end of these environments are carried out, is reversed in relation to the order in which these things should be carried out.
This can be made obvious by patching the \begin
- and \end
-command so that these commands also deliver a message about which environment is currently carried out:
The following example delivers messages in the order
BEGINNING ENVIRONMENT: document
BEGINNING ENVIRONMENT: mynewenv
BEGINNING ENVIRONMENT: math
ENDING ENVIRONMENT: mynewenv
ENDING ENVIRONMENT: math
ENDING ENVIRONMENT: document
But messages should be delivered in the order
BEGINNING ENVIRONMENT: document
BEGINNING ENVIRONMENT: mynewenv
BEGINNING ENVIRONMENT: math
ENDING ENVIRONMENT: math
ENDING ENVIRONMENT: mynewenv
ENDING ENVIRONMENT: document
\documentclass{article}
\makeatletter
\newenvironment{mynewenv}[1]{\begin{#1}}%
{\expandafter\end\expandafter{\@currenvir}}%
%%
\expandafter\def\csname begin \endcsname#1{%
\message{^^JBEGINNING ENVIRONMENT: \detokenize{#1}}%
\UseHook{env/#1/before}%
\@ifundefined{#1}%
{\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
{\def\reserved@a{\def\@currenvir{#1}\edef\@currenvline{\on@line}%
\@execute@begin@hook{#1}\csname #1\endcsname}}%
\@ignorefalse
\begingroup
\@endpefalse
\reserved@a
}%
%%
\expandafter\def\csname end \endcsname#1{%
\message{^^JENDING ENVIRONMENT: \detokenize{#1}}%
\romannumeral
\IfHookEmptyTF{env/#1/end}%
{\expandafter\z@}%
{\z@\UseHook{env/#1/end}}%
\csname end#1\endcsname
\@checkend{#1}%
\expandafter\endgroup\if@endpe\@doendpe\fi
\UseHook{env/#1/after}%
\if@ignore \@ignorefalse\ignorespaces\fi
}%
\makeatother
\begin{document}
\begin{mynewenv}{math}
1+1
\end{mynewenv}
\end{document}
What you can do is have "mynewenv" collect everything verbatimized until reaching \end{mynewenv}
and via \scantokens
spit out either
\end{mynewnv}\begin{#1}<collected stuff>\end{#1}
or
\begin{#1}<collected stuff>\end{#1}\end{mynewnv}
.
So some time ago I wrote my own interface
\UD@GatherCodeSnippetLoop{<non-special characters gathered so far>}%
{<subset of name of environment gathered so far>}%
{<tokens to apply to stuff gathered>}%
<non-special characters>\end{<name of environment>}
which switches to verbatim-catcode-régime and gathers everything in catcode-12-régime until encountering \end{<name of environment>}
, switches back to normal catcode-régime, passes the tokens gathered as a brace-nested undelimited argument behind <tokens to apply to stuff gathered>
and carries out \end{<name of environment>}
.
Within \newenvironment
you can use it as follows:
\newenvironment{foobar}[<args>][<opt-default>]{%
<stuff using parameters according to <args> >
\UD@GatherCodeSnippetLoop{<non-special characters gathered so far>}%
{<subset of name of environment gathered so far>}%
{<tokens to apply to stuff gathered>}%
}{%
<code at end of environment>
}%
The environment delivers something similar to
<tokens to apply to stuff gathered>{<stuff gathered in catcode-12-régime>}
<tokens to apply to stuff gathered>
can consist of directives for prepending and appending more stuff and passing things to \scantokens
. This can be tricky because with \scantokens
you need to ensure that things get re-tokenized correctly.
<tokens to apply to stuff gathered>
must also trigger carrying out \end{foobar}
as the sequence \end{foobar}
occurring in the .tex-input-file is swallowed by \UD@GatherCodeSnippetLoop
as the marker which denotes where to end gathering material in verbatim-category-code-régime.
Environments that use \UD@GatherCodeSnippetLoop
have some shortcomings:
- They cannot be nested!
- They cannot be called by macros/
\the
-expansion of token-registers.
\makeatletter
%%///////////// Code for interface \UD@GatherCodeSnippetLoop and ///////////////
%%///////////// and all suplementary things ////////////////////////////////////
%%===============================================================================
%% End \romannumeral-driven expansion safely:
%%===============================================================================
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%===============================================================================
%% Check whether argument is empty:
%%===============================================================================
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\UD@stopromannumeral\@secondoftwo}{%
\expandafter\UD@stopromannumeral\@firstoftwo}%
}%
\newcommand\UD@exchange[2]{#2#1}%
%%===============================================================================
%% Loop for replacing catcode-10-spaces by catcode-12-spaces
%%===============================================================================
\begingroup
\def\UD@ReplaceSpace#1{%
\endgroup
\@ifdefinable\UD@ReplaceSpace{\long\def\UD@ReplaceSpace##1 {##1#1}}%
}%
\catcode`\ =12\relax
\UD@ReplaceSpace{ }%
\@ifdefinable\UD@GobbleToSpace{\long\def\UD@GobbleToSpace#1 {}}%
\newcommand\UD@SpaceReplaceLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToSpace#1 }{%
\UD@stopromannumeral#1%
}{%
\expandafter\UD@SpaceReplaceLoop\expandafter{\UD@ReplaceSpace#1}%
}%
}%
%%===============================================================================
%% Check if string of non-special character-tokens is substring
%% of another string of non-special character-tokens:
%%===============================================================================
%% \UD@checkstringsubsetof{<possible substring>}{<string>}%
%% {<tokens if <possible substring> and <string> are equal>}%
%% {<tokens if <possible substring> is strict subset of <string>>}%
%% {<<tokens if <possible substring> is not subset of <string>>}%
%% The length of <possible substring> must not exceed the length of <string>!!!
\newcommand\UD@checkstringsubsetof[5]{%
\UD@checkstringsubsetofloop#1\relax#2\relax{{#3}{#4}}{#5}%
}%
\@ifdefinable\UD@checkstringsubsetofloop{%
\def\UD@checkstringsubsetofloop#1#2\relax#3#4\relax{%
\if\string#1\string#3\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{%
\ifx\relax#2\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{%
\ifx\relax#4\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\expandafter\@firstoftwo\@firstoftwo}{\expandafter\@secondoftwo\@firstoftwo}%
}%
{\UD@checkstringsubsetofloop#2\relax#4\relax}%
}{\expandafter\@secondoftwo}%
}%
}%
%%===============================================================================
%% Gather non-special character-tokens until encountering
%% \end{<name of environment>} :
%%===============================================================================
%% \UD@GatherCodeSnippetLoop{<non-special characters gathered so far>}%
%% {<subset of name of environment gathered so far>}%
%% {<tokens to apply to stuff gathered>}%
%% <non-special characters>\end{<name of environment>}
%%
%% Character-wise gathers <non-special characters>, replaces any non-space by its
%% \catcode-12-pendant. (Space is handled by giving it catcode 12 before applying
%% the routine.)
%% Then does
%% <tokens to apply to stuff gathered>{<non-special characters gathered so far>}
\newcommand\UD@GatherCodeSnippetLoop{%
\begingroup
\let\@tempa\@currenvir
\@onelevel@sanitize\@tempa
\expandafter\endgroup
\expandafter\UD@@GatherCodeSnippetLoop
\expandafter{\romannumeral\expandafter\UD@SpaceReplaceLoop\expandafter{\@tempa}}%
}%
\newcommand\UD@@GatherCodeSnippetLoop[1]{%
\begingroup
\let\do\@makeother % <- this and the next line switch to
\dospecials % verbatim-category-code-régime.
\do\^^I%
\do\^^M%
\begingroup
\escapechar=-1\relax
\edef\@tempa{\string\\end\string{#1\string}}%
\expandafter\endgroup
\expandafter\UD@@@GatherCodeSnippetLoop
\expandafter{\@tempa}{#1}%
}%
\newcommand\UD@@@GatherCodeSnippetLoop[6]{%
\UD@checkstringsubsetof{#4#6}{#1}{%
\endgroup#5{#3}%
}{%
\expandafter\UD@exchange\expandafter{\expandafter{%
\romannumeral
\expandafter\UD@exchange\expandafter{%
\romannumeral\UD@StringifyIfNotSpace{#6}%
}{\UD@stopromannumeral#4}%
}}{\UD@@@GatherCodeSnippetLoop{#1}{#2}{#3}}{#5}%
}{%
\UD@checkstringsubsetof{#6}{#1}{%
#5{#3#4}%
}{%
\expandafter\UD@exchange\expandafter{\expandafter{%
\romannumeral\UD@StringifyIfNotSpace{#6}%
}}{\UD@@@GatherCodeSnippetLoop{#1}{#2}{#3#4}}{#5}%
}{%
\expandafter\UD@exchange\expandafter{\expandafter{%
\romannumeral
\expandafter\UD@exchange\expandafter{%
\romannumeral\UD@StringifyIfNotSpace{#6}%
}{\UD@stopromannumeral#3#4}%
}}{\UD@@@GatherCodeSnippetLoop{#1}{#2}}{}{#5}%
}%
}%
}%
\newcommand\UD@StringifyIfNotSpace[1]{%
\if\string#1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\UD@stopromannumeral}{\expandafter\UD@stopromannumeral\string}#1%
}%
%%///////////// End of code for interface \UD@GatherCodeSnippetLoop /////////////
\makeatother
\makeatletter
%%///////////// Code for environment mynewenv ///////////////////////////////////
\newenvironment{mynewenv}[1]{%
\UD@GatherCodeSnippetLoop{}{}{\wrapmynewenv{#1}}%
}{}%
\begingroup
\def\wrapmynewenv#1#2#3{%
\endgroup
\newcommand\wrapmynewenv[2]{%
\begingroup
\newlinechar=\endlinechar
\scantokens\expandafter{\string\endgroup#1{##1}##2#2{##1}#3}%
\end{mynewenv}%
}%
}%
\catcode`\%=12\relax
\expandafter\expandafter\expandafter\wrapmynewenv
\expandafter\expandafter\expandafter{\expandafter
\string\expandafter\begin\expandafter}\expandafter
{\string\end}{%}%
%%///////////// End of code for environment mynewenv /////////////////////////////
\makeatother
\documentclass{article}
%\makeatletter
%\expandafter\def\csname begin \endcsname#1{%
% \message{^^JBEGINNING ENVIRONMENT: \detokenize{#1}}%
% \UseHook{env/#1/before}%
% \@ifundefined{#1}%
% {\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
% {\def\reserved@a{\def\@currenvir{#1}\edef\@currenvline{\on@line}%
% \@execute@begin@hook{#1}\csname #1\endcsname}}%
% \@ignorefalse
% \begingroup
% \@endpefalse
% \reserved@a
%}%
%%
%\expandafter\def\csname end \endcsname#1{%
% \message{^^JENDING ENVIRONMENT: \detokenize{#1}}%
% \romannumeral
% \IfHookEmptyTF{env/#1/end}%
% {\expandafter\z@}%
% {\z@\UseHook{env/#1/end}}%
% \csname end#1\endcsname
% \@checkend{#1}%
% \expandafter\endgroup\if@endpe\@doendpe\fi
% \UseHook{env/#1/after}%
% \if@ignore \@ignorefalse\ignorespaces\fi
%}%
%\makeatother
\begin{document}
\noindent
\begin{mynewenv}{math}
1+1
\end{mynewenv}
\begin{mynewenv}{verbatim*}
#1 $_ {^ blebb
\end{mynewenv}
\end{document}
\end{env}
, and in this construction it is hidden. Additionally, that is not how\newenvironment
work, it takes two{}
after the[1]
, not one like you have here.