Use newcommand in newenvironment - content of environment is argument of newcommand












6















I want to create an environment, that generates a new command. There are some similar examples on google, but nothing fits exactly.



The minimal (not) working example shows best, what I want:



documentclass[12pt,a4paper]{article}
usepackage[utf8]{inputenc}

setlength{parindent}{0pt}

%Thats my environment:
newenvironment{LHZZ}[1]{
newcommand{csname LH#1endcsname }[1]bgroup
}{egroup}

%Thats the use of it. It is very important, that I can use arguments:
begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}


The environment above should (but doesnt) equal the following:



% not part of the code !!!!!
newcommand{LHXY}[1]{
write stuff here

refer to #1
}


The following is the call in the document.



begin{document}
LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
end{document}


The output should be:




write stuff here



refer to parameter




It doesnt work. It says csname is already defined. But I dont want to define csname. It is just the first command inside the argument. What do I have to change, to make this work?



Edit: There is a purpose for this, what seems to be code golfing. This should lead into a package which can be used by people who are not Tex-safe. The package is for making brochures for marriages, church service, etc. easily.



Edit 2:
I sticked to one of the given solutions as far as possible and far as I understood it. Unfortunately, I need one optional parameter. To understand, what is the meaning of this quirky code, have a look at the example songbook and the call of it. The almost final version as a still not working MWE:



%Business as usual
documentclass[12pt,a4paper]{book}
usepackage[utf8]{inputenc}
usepackage[german]{babel}
usepackage{environ}

%This sets a default value
newcommand{LHliederStandard}{n}

%This calls the environment(s)
newcommand{LHsong}[3][LHliederStandard]{
csname LH#2endcsname[#1]#3 %indirect call of what is defined in Liederbuch environment
}

makeatletter
%This is the Liederbuch environment (Liederbuch = songbook)
NewEnviron{Liederbuch}[1]{
xdefLB@my@temp{
noexpandnewcommand{csname LH#1endcsname}[2][relax]{
unexpandedexpandafter{BODY}
}
}
aftergroupLB@my@temp
}
makeatother

%This is the Lied environment (Lied = song)
NewEnviron{Lied}[2]{
ifnumnumexpr#2=numexpr##3 %the double # refers to parameter of the level above, or doesnt it.
ifnumpdfstrcmp{#1}{##2}=0
BODY
fi
fi
}

%example for a songbook
begin{Liederbuch}{songbook}

begin{Lied}{n}{1}
song 1 mode n
end{Lied}

begin{Lied}{nt}{2}
song 2 mode nt
end{Lied}

end{Liederbuch}

%call of the songbook
begin{document}

LHsong{songbook}{1} %calls song 1 mode n
LHsong[nt]{songbook}{2} %calls song 2 mode nt
%hypothetical other songbook
LHsong[n]{childrensongs}{35}

end{document}









share|improve this question

























  • You need to expandafter the newcommand relative to the stuff which comes next. Not sure whether this works with newcommand, though. But probably you want to look at the environ package.

    – cfr
    Apr 9 '16 at 12:49











  • This can't work this way -- you can't grab the environment content like this.

    – user31729
    Apr 9 '16 at 12:49













  • I used expandafter in some tries, but it didn't work.

    – MaestroGlanz
    Apr 9 '16 at 12:51











  • That's why I said you should look at environ.

    – cfr
    Apr 9 '16 at 23:02
















6















I want to create an environment, that generates a new command. There are some similar examples on google, but nothing fits exactly.



The minimal (not) working example shows best, what I want:



documentclass[12pt,a4paper]{article}
usepackage[utf8]{inputenc}

setlength{parindent}{0pt}

%Thats my environment:
newenvironment{LHZZ}[1]{
newcommand{csname LH#1endcsname }[1]bgroup
}{egroup}

%Thats the use of it. It is very important, that I can use arguments:
begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}


The environment above should (but doesnt) equal the following:



% not part of the code !!!!!
newcommand{LHXY}[1]{
write stuff here

refer to #1
}


The following is the call in the document.



begin{document}
LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
end{document}


The output should be:




write stuff here



refer to parameter




It doesnt work. It says csname is already defined. But I dont want to define csname. It is just the first command inside the argument. What do I have to change, to make this work?



Edit: There is a purpose for this, what seems to be code golfing. This should lead into a package which can be used by people who are not Tex-safe. The package is for making brochures for marriages, church service, etc. easily.



Edit 2:
I sticked to one of the given solutions as far as possible and far as I understood it. Unfortunately, I need one optional parameter. To understand, what is the meaning of this quirky code, have a look at the example songbook and the call of it. The almost final version as a still not working MWE:



%Business as usual
documentclass[12pt,a4paper]{book}
usepackage[utf8]{inputenc}
usepackage[german]{babel}
usepackage{environ}

%This sets a default value
newcommand{LHliederStandard}{n}

%This calls the environment(s)
newcommand{LHsong}[3][LHliederStandard]{
csname LH#2endcsname[#1]#3 %indirect call of what is defined in Liederbuch environment
}

makeatletter
%This is the Liederbuch environment (Liederbuch = songbook)
NewEnviron{Liederbuch}[1]{
xdefLB@my@temp{
noexpandnewcommand{csname LH#1endcsname}[2][relax]{
unexpandedexpandafter{BODY}
}
}
aftergroupLB@my@temp
}
makeatother

%This is the Lied environment (Lied = song)
NewEnviron{Lied}[2]{
ifnumnumexpr#2=numexpr##3 %the double # refers to parameter of the level above, or doesnt it.
ifnumpdfstrcmp{#1}{##2}=0
BODY
fi
fi
}

%example for a songbook
begin{Liederbuch}{songbook}

begin{Lied}{n}{1}
song 1 mode n
end{Lied}

begin{Lied}{nt}{2}
song 2 mode nt
end{Lied}

end{Liederbuch}

%call of the songbook
begin{document}

LHsong{songbook}{1} %calls song 1 mode n
LHsong[nt]{songbook}{2} %calls song 2 mode nt
%hypothetical other songbook
LHsong[n]{childrensongs}{35}

end{document}









share|improve this question

























  • You need to expandafter the newcommand relative to the stuff which comes next. Not sure whether this works with newcommand, though. But probably you want to look at the environ package.

    – cfr
    Apr 9 '16 at 12:49











  • This can't work this way -- you can't grab the environment content like this.

    – user31729
    Apr 9 '16 at 12:49













  • I used expandafter in some tries, but it didn't work.

    – MaestroGlanz
    Apr 9 '16 at 12:51











  • That's why I said you should look at environ.

    – cfr
    Apr 9 '16 at 23:02














6












6








6


1






I want to create an environment, that generates a new command. There are some similar examples on google, but nothing fits exactly.



The minimal (not) working example shows best, what I want:



documentclass[12pt,a4paper]{article}
usepackage[utf8]{inputenc}

setlength{parindent}{0pt}

%Thats my environment:
newenvironment{LHZZ}[1]{
newcommand{csname LH#1endcsname }[1]bgroup
}{egroup}

%Thats the use of it. It is very important, that I can use arguments:
begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}


The environment above should (but doesnt) equal the following:



% not part of the code !!!!!
newcommand{LHXY}[1]{
write stuff here

refer to #1
}


The following is the call in the document.



begin{document}
LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
end{document}


The output should be:




write stuff here



refer to parameter




It doesnt work. It says csname is already defined. But I dont want to define csname. It is just the first command inside the argument. What do I have to change, to make this work?



Edit: There is a purpose for this, what seems to be code golfing. This should lead into a package which can be used by people who are not Tex-safe. The package is for making brochures for marriages, church service, etc. easily.



Edit 2:
I sticked to one of the given solutions as far as possible and far as I understood it. Unfortunately, I need one optional parameter. To understand, what is the meaning of this quirky code, have a look at the example songbook and the call of it. The almost final version as a still not working MWE:



%Business as usual
documentclass[12pt,a4paper]{book}
usepackage[utf8]{inputenc}
usepackage[german]{babel}
usepackage{environ}

%This sets a default value
newcommand{LHliederStandard}{n}

%This calls the environment(s)
newcommand{LHsong}[3][LHliederStandard]{
csname LH#2endcsname[#1]#3 %indirect call of what is defined in Liederbuch environment
}

makeatletter
%This is the Liederbuch environment (Liederbuch = songbook)
NewEnviron{Liederbuch}[1]{
xdefLB@my@temp{
noexpandnewcommand{csname LH#1endcsname}[2][relax]{
unexpandedexpandafter{BODY}
}
}
aftergroupLB@my@temp
}
makeatother

%This is the Lied environment (Lied = song)
NewEnviron{Lied}[2]{
ifnumnumexpr#2=numexpr##3 %the double # refers to parameter of the level above, or doesnt it.
ifnumpdfstrcmp{#1}{##2}=0
BODY
fi
fi
}

%example for a songbook
begin{Liederbuch}{songbook}

begin{Lied}{n}{1}
song 1 mode n
end{Lied}

begin{Lied}{nt}{2}
song 2 mode nt
end{Lied}

end{Liederbuch}

%call of the songbook
begin{document}

LHsong{songbook}{1} %calls song 1 mode n
LHsong[nt]{songbook}{2} %calls song 2 mode nt
%hypothetical other songbook
LHsong[n]{childrensongs}{35}

end{document}









share|improve this question
















I want to create an environment, that generates a new command. There are some similar examples on google, but nothing fits exactly.



The minimal (not) working example shows best, what I want:



documentclass[12pt,a4paper]{article}
usepackage[utf8]{inputenc}

setlength{parindent}{0pt}

%Thats my environment:
newenvironment{LHZZ}[1]{
newcommand{csname LH#1endcsname }[1]bgroup
}{egroup}

%Thats the use of it. It is very important, that I can use arguments:
begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}


The environment above should (but doesnt) equal the following:



% not part of the code !!!!!
newcommand{LHXY}[1]{
write stuff here

refer to #1
}


The following is the call in the document.



begin{document}
LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
end{document}


The output should be:




write stuff here



refer to parameter




It doesnt work. It says csname is already defined. But I dont want to define csname. It is just the first command inside the argument. What do I have to change, to make this work?



Edit: There is a purpose for this, what seems to be code golfing. This should lead into a package which can be used by people who are not Tex-safe. The package is for making brochures for marriages, church service, etc. easily.



Edit 2:
I sticked to one of the given solutions as far as possible and far as I understood it. Unfortunately, I need one optional parameter. To understand, what is the meaning of this quirky code, have a look at the example songbook and the call of it. The almost final version as a still not working MWE:



%Business as usual
documentclass[12pt,a4paper]{book}
usepackage[utf8]{inputenc}
usepackage[german]{babel}
usepackage{environ}

%This sets a default value
newcommand{LHliederStandard}{n}

%This calls the environment(s)
newcommand{LHsong}[3][LHliederStandard]{
csname LH#2endcsname[#1]#3 %indirect call of what is defined in Liederbuch environment
}

makeatletter
%This is the Liederbuch environment (Liederbuch = songbook)
NewEnviron{Liederbuch}[1]{
xdefLB@my@temp{
noexpandnewcommand{csname LH#1endcsname}[2][relax]{
unexpandedexpandafter{BODY}
}
}
aftergroupLB@my@temp
}
makeatother

%This is the Lied environment (Lied = song)
NewEnviron{Lied}[2]{
ifnumnumexpr#2=numexpr##3 %the double # refers to parameter of the level above, or doesnt it.
ifnumpdfstrcmp{#1}{##2}=0
BODY
fi
fi
}

%example for a songbook
begin{Liederbuch}{songbook}

begin{Lied}{n}{1}
song 1 mode n
end{Lied}

begin{Lied}{nt}{2}
song 2 mode nt
end{Lied}

end{Liederbuch}

%call of the songbook
begin{document}

LHsong{songbook}{1} %calls song 1 mode n
LHsong[nt]{songbook}{2} %calls song 2 mode nt
%hypothetical other songbook
LHsong[n]{childrensongs}{35}

end{document}






macros environments






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 12 '16 at 12:46







MaestroGlanz

















asked Apr 9 '16 at 12:44









MaestroGlanzMaestroGlanz

1,177315




1,177315













  • You need to expandafter the newcommand relative to the stuff which comes next. Not sure whether this works with newcommand, though. But probably you want to look at the environ package.

    – cfr
    Apr 9 '16 at 12:49











  • This can't work this way -- you can't grab the environment content like this.

    – user31729
    Apr 9 '16 at 12:49













  • I used expandafter in some tries, but it didn't work.

    – MaestroGlanz
    Apr 9 '16 at 12:51











  • That's why I said you should look at environ.

    – cfr
    Apr 9 '16 at 23:02



















  • You need to expandafter the newcommand relative to the stuff which comes next. Not sure whether this works with newcommand, though. But probably you want to look at the environ package.

    – cfr
    Apr 9 '16 at 12:49











  • This can't work this way -- you can't grab the environment content like this.

    – user31729
    Apr 9 '16 at 12:49













  • I used expandafter in some tries, but it didn't work.

    – MaestroGlanz
    Apr 9 '16 at 12:51











  • That's why I said you should look at environ.

    – cfr
    Apr 9 '16 at 23:02

















You need to expandafter the newcommand relative to the stuff which comes next. Not sure whether this works with newcommand, though. But probably you want to look at the environ package.

– cfr
Apr 9 '16 at 12:49





You need to expandafter the newcommand relative to the stuff which comes next. Not sure whether this works with newcommand, though. But probably you want to look at the environ package.

– cfr
Apr 9 '16 at 12:49













This can't work this way -- you can't grab the environment content like this.

– user31729
Apr 9 '16 at 12:49







This can't work this way -- you can't grab the environment content like this.

– user31729
Apr 9 '16 at 12:49















I used expandafter in some tries, but it didn't work.

– MaestroGlanz
Apr 9 '16 at 12:51





I used expandafter in some tries, but it didn't work.

– MaestroGlanz
Apr 9 '16 at 12:51













That's why I said you should look at environ.

– cfr
Apr 9 '16 at 23:02





That's why I said you should look at environ.

– cfr
Apr 9 '16 at 23:02










4 Answers
4






active

oldest

votes


















4














The command form is easier:



documentclass{article}

newcommand{LHZZ}[2]{%
expandafternewcommandcsname LH#1endcsname[1]{#2}}%
}

begin{document}

LHZZ{XY}{%
write stuff here

refer to #1%
}

LHXY{parameter}

end{document}


If you really insist in using an environment, use environ:



documentclass{article}
usepackage{environ}

makeatletter
NewEnviron{LHZZ}[1]{%
edefmaestroglanz@temp{%
unexpanded{expandaftergdefcsname LH#1endcsname}####1{unexpandedexpandafter{BODY}}%
}%
maestroglanz@temp
}
makeatother

begin{document}

begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}

LHXY{parameter}

end{document}


enter image description here





An implementation using xparse and expl3; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.



documentclass{article}
usepackage{environ,xparse}

ExplSyntaxOn
NewEnviron{LHZZ}[1]
{
cs_set_protected:cV { LH#1:n } BODY
cs_if_free:cTF { LH#1 }
{
cs_gset_eq:cc { LH#1 }{ LH#1:n }
}
{
msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
}
}
cs_generate_variant:Nn cs_set_protected:Nn { cV }
msg_new:nnnn { maestroglanz/LH } { already-defined }
{
LH#1~already~defined
}
{
You~used~token_to_str:N begin{LHZZ}{#1}~before
}
ExplSyntaxOff

begin{document}

begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}

LHXY{parameter}

begin{LHZZ}{XY}aend{LHZZ}

end{document}


Without the error check, the code part would look like



ExplSyntaxOn
NewEnviron{LHZZ}[1]
{
cs_set_protected:cV { LH#1:n } BODY
cs_gset_eq:cc { LH#1 }{ LH#1:n }
}
cs_generate_variant:Nn cs_set_protected:Nn { cV }
ExplSyntaxOff


Update



With xparse released 2019-05-03 the code can become



documentclass{article}
usepackage{xparse}

ExplSyntaxOn
NewDocumentEnvironment{LHZZ}{m +b}
{
cs_set_protected:cn { LH#1:n } { #2 }
cs_if_free:cTF { LH#1 }
{
cs_gset_eq:cc { LH#1 }{ LH#1:n }
}
{
msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
}
}{}
msg_new:nnnn { maestroglanz/LH } { already-defined }
{
LH#1~already~defined
}
{
You~used~token_to_str:N begin{LHZZ}{#1}~before
}
ExplSyntaxOff

begin{document}

begin{LHZZ}{XY}
write stuff here

refer to #1
end{LHZZ}

LHXY{parameter}

begin{LHZZ}{XY}aend{LHZZ}

end{document}





share|improve this answer


























  • Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

    – cfr
    Apr 9 '16 at 23:09











  • @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

    – egreg
    Apr 9 '16 at 23:12













  • @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

    – egreg
    Apr 9 '16 at 23:30













  • OK. I just wanted to make sure I wasn't (that) crazy.

    – cfr
    Apr 9 '16 at 23:31











  • So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

    – cfr
    Apr 10 '16 at 0:23



















3














Here is your minimal example turned into a working one:



documentclass[a4paper]{article}
usepackage[T1]{fontenc}
usepackage[ascii]{inputenc}
usepackage{environ}

makeatletter

@ifdefinable@my@temporary{} % check availability of the name
% That's my environment:
NewEnviron{LHZZ}[1]{%
let newcommand relax
protected@xdef@my@temporary{%
newcommand{csname LH#1endcsname}[1]{BODY}}%
aftergroup@my@temporary
}

makeatother



begin{document}

% That's the use of it:
begin{LHZZ}{XY}
write stuff here

refer to ##1 % sorry, doubling "#" is necessary here
end{LHZZ}

LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}

end{document}




Edit: I think using newcommand instead of globaledef (see Christian’s answer; note, however, that globaledef is exactly the same as xdef) does have some added value, because one retains, for example, the ability to define a default argument:



documentclass[a4paper]{article}
usepackage[T1]{fontenc}
usepackage[ascii]{inputenc}
usepackage{environ}

makeatletter

@ifdefinable@my@temporary@x{} % check availability of the names
@ifdefinable@my@temporary@y{}
% That's my environment:
NewEnviron{LHZZ}[1]{%
let newcommand relax
protected@xdef@my@temporary@x{%
newcommand{csname LH#1endcsname}[1]{BODY}
}%
% ... but this one works too (the astersik is there only to illustrate
% another possibility: define a non-"long" command):
protected@xdef@my@temporary@y{%
newcommand*{csname MG#1endcsname}[1][default]{BODY}
}%
aftergroup@my@temporary@x
aftergroup@my@temporary@y
}

makeatother



begin{document}

% That's the use of it:
begin{LHZZ}{XY}
write stuff here
refer to ##1par % sorry, doubling "#" is necessary here
end{LHZZ}

Text before.

LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
MGXY[parameter]
MGXY

Text after.

end{document}




Edit 2: Always double-check that the brain is connected before writing to TeX.SX! (Will it be, now?) Here is a cleaner implementation of the same basic idea:



documentclass[a4paper]{article}
usepackage[T1]{fontenc}
usepackage[ascii]{inputenc}
usepackage{environ}

makeatletter

@ifdefinable@my@temporary@x{} % check availability of the names
@ifdefinable@my@temporary@y{}
% That's my environment:
NewEnviron{LHZZ}[1]{%
xdef@my@temporary@x{%
noexpandnewcommand{csname LH#1endcsname}[1]{%
unexpandedexpandafter{BODY}%
}%
}%
% ... but this one works too (the astersik is there only to illustrate
% another possibility: define a non-"long" command):
xdef@my@temporary@y{%
noexpandnewcommand*{csname MG#1endcsname}[1][default]{%
unexpandedexpandafter{BODY}%
}%
}%
aftergroup@my@temporary@x
aftergroup@my@temporary@y
% Obviously, in a real application you'd choose only one of the two
% possibiities.
}

makeatother



begin{document}

begingroup % to show that normal scoping is obeyed

% That's the use of it:
begin{LHZZ}{XY}
write stuff here
refer to texttt{#1}par % doubling the "#" is no longer necessary
end{LHZZ}

Now verb|LHXY| is
begin{flushleft}
ttfamily meaningLHXY
end{flushleft}

Text before.

LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
MGXY[parameter]
MGXY

Text after.

endgroup

Here verb|LHXY| is textbf{%
ifdefined LHXY definedelse not definedfi
}.

end{document}


But I’d better follow @egreg’s solicitation… (see comments ;-)






share|improve this answer


























  • No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

    – egreg
    Apr 9 '16 at 13:54











  • @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

    – GuM
    Apr 9 '16 at 14:04











  • You have to work harder, for that. ;-)

    – egreg
    Apr 9 '16 at 14:05











  • Don't you like the expl3 version?

    – egreg
    Apr 9 '16 at 14:40






  • 1





    @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

    – GuM
    Apr 13 '16 at 9:42





















2














I think this is code golfing however...



expandafternewcommandcsname ....endcsname{... won't work outside -- it's a local definition.



globalexpandafternewcommand...won't work neither due to expansion, but globalexpandafterdefcsname... would work, but since the environment body shall be grabbed, the BODY macro must be expanded first, otherwise it would be undefined outside of the environment, so either use expandafterxdefcsname.... or globalexpandafteredefcsname...



documentclass[12pt,a4paper]{article}
usepackage[utf8]{inputenc}


usepackage{environ}
setlength{parindent}{0pt}


NewEnviron{LHZZ}[1]{%
longglobalexpandafteredefcsname LH#1endcsname##1{BODY ##1}
}

begin{LHZZ}{XY}
write stuff here

Other stuff here
end{LHZZ}


begin{document}


LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
end{document}





share|improve this answer
























  • Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

    – GuM
    Apr 9 '16 at 13:44











  • @GustavoMezzetti: No worries, you provided a different answer

    – user31729
    Apr 9 '16 at 14:28



















1














If you are using environ package then you can write something like this:



NewEnviron{LHZZ}[1]{%
expandaftergdefcsname LH#1expandafterendcsname
expandafter##expandafter1expandafter{BODY}}


Note, that the code is much more compact than the usage of eTeX's unexpanded, four hashes, etc...






share|improve this answer























    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "85"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f303354%2fuse-newcommand-in-newenvironment-content-of-environment-is-argument-of-newc%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4














    The command form is easier:



    documentclass{article}

    newcommand{LHZZ}[2]{%
    expandafternewcommandcsname LH#1endcsname[1]{#2}}%
    }

    begin{document}

    LHZZ{XY}{%
    write stuff here

    refer to #1%
    }

    LHXY{parameter}

    end{document}


    If you really insist in using an environment, use environ:



    documentclass{article}
    usepackage{environ}

    makeatletter
    NewEnviron{LHZZ}[1]{%
    edefmaestroglanz@temp{%
    unexpanded{expandaftergdefcsname LH#1endcsname}####1{unexpandedexpandafter{BODY}}%
    }%
    maestroglanz@temp
    }
    makeatother

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    end{document}


    enter image description here





    An implementation using xparse and expl3; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.



    documentclass{article}
    usepackage{environ,xparse}

    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}


    Without the error check, the code part would look like



    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    ExplSyntaxOff


    Update



    With xparse released 2019-05-03 the code can become



    documentclass{article}
    usepackage{xparse}

    ExplSyntaxOn
    NewDocumentEnvironment{LHZZ}{m +b}
    {
    cs_set_protected:cn { LH#1:n } { #2 }
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }{}
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}





    share|improve this answer


























    • Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

      – cfr
      Apr 9 '16 at 23:09











    • @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

      – egreg
      Apr 9 '16 at 23:12













    • @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

      – egreg
      Apr 9 '16 at 23:30













    • OK. I just wanted to make sure I wasn't (that) crazy.

      – cfr
      Apr 9 '16 at 23:31











    • So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

      – cfr
      Apr 10 '16 at 0:23
















    4














    The command form is easier:



    documentclass{article}

    newcommand{LHZZ}[2]{%
    expandafternewcommandcsname LH#1endcsname[1]{#2}}%
    }

    begin{document}

    LHZZ{XY}{%
    write stuff here

    refer to #1%
    }

    LHXY{parameter}

    end{document}


    If you really insist in using an environment, use environ:



    documentclass{article}
    usepackage{environ}

    makeatletter
    NewEnviron{LHZZ}[1]{%
    edefmaestroglanz@temp{%
    unexpanded{expandaftergdefcsname LH#1endcsname}####1{unexpandedexpandafter{BODY}}%
    }%
    maestroglanz@temp
    }
    makeatother

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    end{document}


    enter image description here





    An implementation using xparse and expl3; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.



    documentclass{article}
    usepackage{environ,xparse}

    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}


    Without the error check, the code part would look like



    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    ExplSyntaxOff


    Update



    With xparse released 2019-05-03 the code can become



    documentclass{article}
    usepackage{xparse}

    ExplSyntaxOn
    NewDocumentEnvironment{LHZZ}{m +b}
    {
    cs_set_protected:cn { LH#1:n } { #2 }
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }{}
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}





    share|improve this answer


























    • Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

      – cfr
      Apr 9 '16 at 23:09











    • @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

      – egreg
      Apr 9 '16 at 23:12













    • @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

      – egreg
      Apr 9 '16 at 23:30













    • OK. I just wanted to make sure I wasn't (that) crazy.

      – cfr
      Apr 9 '16 at 23:31











    • So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

      – cfr
      Apr 10 '16 at 0:23














    4












    4








    4







    The command form is easier:



    documentclass{article}

    newcommand{LHZZ}[2]{%
    expandafternewcommandcsname LH#1endcsname[1]{#2}}%
    }

    begin{document}

    LHZZ{XY}{%
    write stuff here

    refer to #1%
    }

    LHXY{parameter}

    end{document}


    If you really insist in using an environment, use environ:



    documentclass{article}
    usepackage{environ}

    makeatletter
    NewEnviron{LHZZ}[1]{%
    edefmaestroglanz@temp{%
    unexpanded{expandaftergdefcsname LH#1endcsname}####1{unexpandedexpandafter{BODY}}%
    }%
    maestroglanz@temp
    }
    makeatother

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    end{document}


    enter image description here





    An implementation using xparse and expl3; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.



    documentclass{article}
    usepackage{environ,xparse}

    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}


    Without the error check, the code part would look like



    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    ExplSyntaxOff


    Update



    With xparse released 2019-05-03 the code can become



    documentclass{article}
    usepackage{xparse}

    ExplSyntaxOn
    NewDocumentEnvironment{LHZZ}{m +b}
    {
    cs_set_protected:cn { LH#1:n } { #2 }
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }{}
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}





    share|improve this answer















    The command form is easier:



    documentclass{article}

    newcommand{LHZZ}[2]{%
    expandafternewcommandcsname LH#1endcsname[1]{#2}}%
    }

    begin{document}

    LHZZ{XY}{%
    write stuff here

    refer to #1%
    }

    LHXY{parameter}

    end{document}


    If you really insist in using an environment, use environ:



    documentclass{article}
    usepackage{environ}

    makeatletter
    NewEnviron{LHZZ}[1]{%
    edefmaestroglanz@temp{%
    unexpanded{expandaftergdefcsname LH#1endcsname}####1{unexpandedexpandafter{BODY}}%
    }%
    maestroglanz@temp
    }
    makeatother

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    end{document}


    enter image description here





    An implementation using xparse and expl3; the largest part of the code is the definition of the error messages in case the environment is called twice with the same argument.



    documentclass{article}
    usepackage{environ,xparse}

    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}


    Without the error check, the code part would look like



    ExplSyntaxOn
    NewEnviron{LHZZ}[1]
    {
    cs_set_protected:cV { LH#1:n } BODY
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    cs_generate_variant:Nn cs_set_protected:Nn { cV }
    ExplSyntaxOff


    Update



    With xparse released 2019-05-03 the code can become



    documentclass{article}
    usepackage{xparse}

    ExplSyntaxOn
    NewDocumentEnvironment{LHZZ}{m +b}
    {
    cs_set_protected:cn { LH#1:n } { #2 }
    cs_if_free:cTF { LH#1 }
    {
    cs_gset_eq:cc { LH#1 }{ LH#1:n }
    }
    {
    msg_error:nnn { maestroglanz/LH } { already-defined } { #1 }
    }
    }{}
    msg_new:nnnn { maestroglanz/LH } { already-defined }
    {
    LH#1~already~defined
    }
    {
    You~used~token_to_str:N begin{LHZZ}{#1}~before
    }
    ExplSyntaxOff

    begin{document}

    begin{LHZZ}{XY}
    write stuff here

    refer to #1
    end{LHZZ}

    LHXY{parameter}

    begin{LHZZ}{XY}aend{LHZZ}

    end{document}






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Mar 8 at 14:42

























    answered Apr 9 '16 at 13:45









    egregegreg

    727k8819223231




    727k8819223231













    • Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

      – cfr
      Apr 9 '16 at 23:09











    • @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

      – egreg
      Apr 9 '16 at 23:12













    • @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

      – egreg
      Apr 9 '16 at 23:30













    • OK. I just wanted to make sure I wasn't (that) crazy.

      – cfr
      Apr 9 '16 at 23:31











    • So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

      – cfr
      Apr 10 '16 at 0:23



















    • Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

      – cfr
      Apr 9 '16 at 23:09











    • @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

      – egreg
      Apr 9 '16 at 23:12













    • @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

      – egreg
      Apr 9 '16 at 23:30













    • OK. I just wanted to make sure I wasn't (that) crazy.

      – cfr
      Apr 9 '16 at 23:31











    • So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

      – cfr
      Apr 10 '16 at 0:23

















    Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

    – cfr
    Apr 9 '16 at 23:09





    Could you explain briefly (if this is possible) when to use cs_set_protected in a way which doesn't assume an understanding of the corresponding TeX macros? If this query asks something unmanageably big, please just ignore it. I don't know enough to have a sense of whether the question is a reasonable one or not.

    – cfr
    Apr 9 '16 at 23:09













    @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

    – egreg
    Apr 9 '16 at 23:12







    @cfr Basically, you always use _protected, unless you have good reasons not to; the good reason is that you want the function is expandable in x arguments. For instance, the analog of thesection should not be protected.

    – egreg
    Apr 9 '16 at 23:12















    @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

    – egreg
    Apr 9 '16 at 23:30







    @cfr Yes, but it wasn't right. Your impression about NewDocumentCommand is wrong as well.

    – egreg
    Apr 9 '16 at 23:30















    OK. I just wanted to make sure I wasn't (that) crazy.

    – cfr
    Apr 9 '16 at 23:31





    OK. I just wanted to make sure I wasn't (that) crazy.

    – cfr
    Apr 9 '16 at 23:31













    So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

    – cfr
    Apr 10 '16 at 0:23





    So I just went through one file adding protecteds and things still seem to work, which I guess means they should be protecteds. But I'm wary of changing the last 3 cases because the first has a note saying that you gave me the code and the other 2 are modelled on the first: % includegraphics bit courtesy of egreg (chat 2015-01-08) cs_new:Npn cfr_includegraphics:nn #1 #2 { includegraphics[#1]{#2} } . I don't know if you can tell from this why this shouldn't be protected?

    – cfr
    Apr 10 '16 at 0:23











    3














    Here is your minimal example turned into a working one:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary{} % check availability of the name
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary{%
    newcommand{csname LH#1endcsname}[1]{BODY}}%
    aftergroup@my@temporary
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here

    refer to ##1 % sorry, doubling "#" is necessary here
    end{LHZZ}

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}

    end{document}




    Edit: I think using newcommand instead of globaledef (see Christian’s answer; note, however, that globaledef is exactly the same as xdef) does have some added value, because one retains, for example, the ability to define a default argument:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary@x{%
    newcommand{csname LH#1endcsname}[1]{BODY}
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    protected@xdef@my@temporary@y{%
    newcommand*{csname MG#1endcsname}[1][default]{BODY}
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to ##1par % sorry, doubling "#" is necessary here
    end{LHZZ}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    end{document}




    Edit 2: Always double-check that the brain is connected before writing to TeX.SX! (Will it be, now?) Here is a cleaner implementation of the same basic idea:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    xdef@my@temporary@x{%
    noexpandnewcommand{csname LH#1endcsname}[1]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    xdef@my@temporary@y{%
    noexpandnewcommand*{csname MG#1endcsname}[1][default]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    % Obviously, in a real application you'd choose only one of the two
    % possibiities.
    }

    makeatother



    begin{document}

    begingroup % to show that normal scoping is obeyed

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to texttt{#1}par % doubling the "#" is no longer necessary
    end{LHZZ}

    Now verb|LHXY| is
    begin{flushleft}
    ttfamily meaningLHXY
    end{flushleft}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    endgroup

    Here verb|LHXY| is textbf{%
    ifdefined LHXY definedelse not definedfi
    }.

    end{document}


    But I’d better follow @egreg’s solicitation… (see comments ;-)






    share|improve this answer


























    • No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

      – egreg
      Apr 9 '16 at 13:54











    • @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

      – GuM
      Apr 9 '16 at 14:04











    • You have to work harder, for that. ;-)

      – egreg
      Apr 9 '16 at 14:05











    • Don't you like the expl3 version?

      – egreg
      Apr 9 '16 at 14:40






    • 1





      @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

      – GuM
      Apr 13 '16 at 9:42


















    3














    Here is your minimal example turned into a working one:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary{} % check availability of the name
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary{%
    newcommand{csname LH#1endcsname}[1]{BODY}}%
    aftergroup@my@temporary
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here

    refer to ##1 % sorry, doubling "#" is necessary here
    end{LHZZ}

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}

    end{document}




    Edit: I think using newcommand instead of globaledef (see Christian’s answer; note, however, that globaledef is exactly the same as xdef) does have some added value, because one retains, for example, the ability to define a default argument:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary@x{%
    newcommand{csname LH#1endcsname}[1]{BODY}
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    protected@xdef@my@temporary@y{%
    newcommand*{csname MG#1endcsname}[1][default]{BODY}
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to ##1par % sorry, doubling "#" is necessary here
    end{LHZZ}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    end{document}




    Edit 2: Always double-check that the brain is connected before writing to TeX.SX! (Will it be, now?) Here is a cleaner implementation of the same basic idea:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    xdef@my@temporary@x{%
    noexpandnewcommand{csname LH#1endcsname}[1]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    xdef@my@temporary@y{%
    noexpandnewcommand*{csname MG#1endcsname}[1][default]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    % Obviously, in a real application you'd choose only one of the two
    % possibiities.
    }

    makeatother



    begin{document}

    begingroup % to show that normal scoping is obeyed

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to texttt{#1}par % doubling the "#" is no longer necessary
    end{LHZZ}

    Now verb|LHXY| is
    begin{flushleft}
    ttfamily meaningLHXY
    end{flushleft}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    endgroup

    Here verb|LHXY| is textbf{%
    ifdefined LHXY definedelse not definedfi
    }.

    end{document}


    But I’d better follow @egreg’s solicitation… (see comments ;-)






    share|improve this answer


























    • No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

      – egreg
      Apr 9 '16 at 13:54











    • @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

      – GuM
      Apr 9 '16 at 14:04











    • You have to work harder, for that. ;-)

      – egreg
      Apr 9 '16 at 14:05











    • Don't you like the expl3 version?

      – egreg
      Apr 9 '16 at 14:40






    • 1





      @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

      – GuM
      Apr 13 '16 at 9:42
















    3












    3








    3







    Here is your minimal example turned into a working one:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary{} % check availability of the name
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary{%
    newcommand{csname LH#1endcsname}[1]{BODY}}%
    aftergroup@my@temporary
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here

    refer to ##1 % sorry, doubling "#" is necessary here
    end{LHZZ}

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}

    end{document}




    Edit: I think using newcommand instead of globaledef (see Christian’s answer; note, however, that globaledef is exactly the same as xdef) does have some added value, because one retains, for example, the ability to define a default argument:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary@x{%
    newcommand{csname LH#1endcsname}[1]{BODY}
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    protected@xdef@my@temporary@y{%
    newcommand*{csname MG#1endcsname}[1][default]{BODY}
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to ##1par % sorry, doubling "#" is necessary here
    end{LHZZ}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    end{document}




    Edit 2: Always double-check that the brain is connected before writing to TeX.SX! (Will it be, now?) Here is a cleaner implementation of the same basic idea:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    xdef@my@temporary@x{%
    noexpandnewcommand{csname LH#1endcsname}[1]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    xdef@my@temporary@y{%
    noexpandnewcommand*{csname MG#1endcsname}[1][default]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    % Obviously, in a real application you'd choose only one of the two
    % possibiities.
    }

    makeatother



    begin{document}

    begingroup % to show that normal scoping is obeyed

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to texttt{#1}par % doubling the "#" is no longer necessary
    end{LHZZ}

    Now verb|LHXY| is
    begin{flushleft}
    ttfamily meaningLHXY
    end{flushleft}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    endgroup

    Here verb|LHXY| is textbf{%
    ifdefined LHXY definedelse not definedfi
    }.

    end{document}


    But I’d better follow @egreg’s solicitation… (see comments ;-)






    share|improve this answer















    Here is your minimal example turned into a working one:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary{} % check availability of the name
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary{%
    newcommand{csname LH#1endcsname}[1]{BODY}}%
    aftergroup@my@temporary
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here

    refer to ##1 % sorry, doubling "#" is necessary here
    end{LHZZ}

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}

    end{document}




    Edit: I think using newcommand instead of globaledef (see Christian’s answer; note, however, that globaledef is exactly the same as xdef) does have some added value, because one retains, for example, the ability to define a default argument:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    let newcommand relax
    protected@xdef@my@temporary@x{%
    newcommand{csname LH#1endcsname}[1]{BODY}
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    protected@xdef@my@temporary@y{%
    newcommand*{csname MG#1endcsname}[1][default]{BODY}
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    }

    makeatother



    begin{document}

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to ##1par % sorry, doubling "#" is necessary here
    end{LHZZ}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    end{document}




    Edit 2: Always double-check that the brain is connected before writing to TeX.SX! (Will it be, now?) Here is a cleaner implementation of the same basic idea:



    documentclass[a4paper]{article}
    usepackage[T1]{fontenc}
    usepackage[ascii]{inputenc}
    usepackage{environ}

    makeatletter

    @ifdefinable@my@temporary@x{} % check availability of the names
    @ifdefinable@my@temporary@y{}
    % That's my environment:
    NewEnviron{LHZZ}[1]{%
    xdef@my@temporary@x{%
    noexpandnewcommand{csname LH#1endcsname}[1]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    % ... but this one works too (the astersik is there only to illustrate
    % another possibility: define a non-"long" command):
    xdef@my@temporary@y{%
    noexpandnewcommand*{csname MG#1endcsname}[1][default]{%
    unexpandedexpandafter{BODY}%
    }%
    }%
    aftergroup@my@temporary@x
    aftergroup@my@temporary@y
    % Obviously, in a real application you'd choose only one of the two
    % possibiities.
    }

    makeatother



    begin{document}

    begingroup % to show that normal scoping is obeyed

    % That's the use of it:
    begin{LHZZ}{XY}
    write stuff here
    refer to texttt{#1}par % doubling the "#" is no longer necessary
    end{LHZZ}

    Now verb|LHXY| is
    begin{flushleft}
    ttfamily meaningLHXY
    end{flushleft}

    Text before.

    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    MGXY[parameter]
    MGXY

    Text after.

    endgroup

    Here verb|LHXY| is textbf{%
    ifdefined LHXY definedelse not definedfi
    }.

    end{document}


    But I’d better follow @egreg’s solicitation… (see comments ;-)







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 9 '16 at 20:39

























    answered Apr 9 '16 at 13:40









    GuMGuM

    16.7k2458




    16.7k2458













    • No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

      – egreg
      Apr 9 '16 at 13:54











    • @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

      – GuM
      Apr 9 '16 at 14:04











    • You have to work harder, for that. ;-)

      – egreg
      Apr 9 '16 at 14:05











    • Don't you like the expl3 version?

      – egreg
      Apr 9 '16 at 14:40






    • 1





      @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

      – GuM
      Apr 13 '16 at 9:42





















    • No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

      – egreg
      Apr 9 '16 at 13:54











    • @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

      – GuM
      Apr 9 '16 at 14:04











    • You have to work harder, for that. ;-)

      – egreg
      Apr 9 '16 at 14:05











    • Don't you like the expl3 version?

      – egreg
      Apr 9 '16 at 14:40






    • 1





      @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

      – GuM
      Apr 13 '16 at 9:42



















    No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

    – egreg
    Apr 9 '16 at 13:54





    No ##1 is actually necessary; more important, you should use protected@xdef, not xdef.

    – egreg
    Apr 9 '16 at 13:54













    @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

    – GuM
    Apr 9 '16 at 14:04





    @egreg: protected@xdef, yes, of course! Thanks for noticing. But concerning the ##, if I try with a single #, it doesn’t work.

    – GuM
    Apr 9 '16 at 14:04













    You have to work harder, for that. ;-)

    – egreg
    Apr 9 '16 at 14:05





    You have to work harder, for that. ;-)

    – egreg
    Apr 9 '16 at 14:05













    Don't you like the expl3 version?

    – egreg
    Apr 9 '16 at 14:40





    Don't you like the expl3 version?

    – egreg
    Apr 9 '16 at 14:40




    1




    1





    @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

    – GuM
    Apr 13 '16 at 9:42







    @MaestroGlanz: csname LH#1endcsname (resp., csname MG#1endcsname) and BODY are expanded (the latter only by one level) when the temporary macros are defined. For example, if #1 is, say, XY, the macro @my@temporary@y will be (globally) defined as newcommand*MGXY[1][default]{<first-level expansion of BODY>}. This temporary macro will be executed when the LHZZ environment is over (aftergroup), so that the MGXY command will be defined in the right scope. Try inserting show@my@temporary@x and/or show@my@temporary@y before the two aftergroups.

    – GuM
    Apr 13 '16 at 9:42













    2














    I think this is code golfing however...



    expandafternewcommandcsname ....endcsname{... won't work outside -- it's a local definition.



    globalexpandafternewcommand...won't work neither due to expansion, but globalexpandafterdefcsname... would work, but since the environment body shall be grabbed, the BODY macro must be expanded first, otherwise it would be undefined outside of the environment, so either use expandafterxdefcsname.... or globalexpandafteredefcsname...



    documentclass[12pt,a4paper]{article}
    usepackage[utf8]{inputenc}


    usepackage{environ}
    setlength{parindent}{0pt}


    NewEnviron{LHZZ}[1]{%
    longglobalexpandafteredefcsname LH#1endcsname##1{BODY ##1}
    }

    begin{LHZZ}{XY}
    write stuff here

    Other stuff here
    end{LHZZ}


    begin{document}


    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    end{document}





    share|improve this answer
























    • Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

      – GuM
      Apr 9 '16 at 13:44











    • @GustavoMezzetti: No worries, you provided a different answer

      – user31729
      Apr 9 '16 at 14:28
















    2














    I think this is code golfing however...



    expandafternewcommandcsname ....endcsname{... won't work outside -- it's a local definition.



    globalexpandafternewcommand...won't work neither due to expansion, but globalexpandafterdefcsname... would work, but since the environment body shall be grabbed, the BODY macro must be expanded first, otherwise it would be undefined outside of the environment, so either use expandafterxdefcsname.... or globalexpandafteredefcsname...



    documentclass[12pt,a4paper]{article}
    usepackage[utf8]{inputenc}


    usepackage{environ}
    setlength{parindent}{0pt}


    NewEnviron{LHZZ}[1]{%
    longglobalexpandafteredefcsname LH#1endcsname##1{BODY ##1}
    }

    begin{LHZZ}{XY}
    write stuff here

    Other stuff here
    end{LHZZ}


    begin{document}


    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    end{document}





    share|improve this answer
























    • Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

      – GuM
      Apr 9 '16 at 13:44











    • @GustavoMezzetti: No worries, you provided a different answer

      – user31729
      Apr 9 '16 at 14:28














    2












    2








    2







    I think this is code golfing however...



    expandafternewcommandcsname ....endcsname{... won't work outside -- it's a local definition.



    globalexpandafternewcommand...won't work neither due to expansion, but globalexpandafterdefcsname... would work, but since the environment body shall be grabbed, the BODY macro must be expanded first, otherwise it would be undefined outside of the environment, so either use expandafterxdefcsname.... or globalexpandafteredefcsname...



    documentclass[12pt,a4paper]{article}
    usepackage[utf8]{inputenc}


    usepackage{environ}
    setlength{parindent}{0pt}


    NewEnviron{LHZZ}[1]{%
    longglobalexpandafteredefcsname LH#1endcsname##1{BODY ##1}
    }

    begin{LHZZ}{XY}
    write stuff here

    Other stuff here
    end{LHZZ}


    begin{document}


    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    end{document}





    share|improve this answer













    I think this is code golfing however...



    expandafternewcommandcsname ....endcsname{... won't work outside -- it's a local definition.



    globalexpandafternewcommand...won't work neither due to expansion, but globalexpandafterdefcsname... would work, but since the environment body shall be grabbed, the BODY macro must be expanded first, otherwise it would be undefined outside of the environment, so either use expandafterxdefcsname.... or globalexpandafteredefcsname...



    documentclass[12pt,a4paper]{article}
    usepackage[utf8]{inputenc}


    usepackage{environ}
    setlength{parindent}{0pt}


    NewEnviron{LHZZ}[1]{%
    longglobalexpandafteredefcsname LH#1endcsname##1{BODY ##1}
    }

    begin{LHZZ}{XY}
    write stuff here

    Other stuff here
    end{LHZZ}


    begin{document}


    LHXY{parameter} %the command LHXY has been created indirectly by begin{LHZZ}
    end{document}






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Apr 9 '16 at 13:01







    user31729




















    • Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

      – GuM
      Apr 9 '16 at 13:44











    • @GustavoMezzetti: No worries, you provided a different answer

      – user31729
      Apr 9 '16 at 14:28



















    • Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

      – GuM
      Apr 9 '16 at 13:44











    • @GustavoMezzetti: No worries, you provided a different answer

      – user31729
      Apr 9 '16 at 14:28

















    Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

    – GuM
    Apr 9 '16 at 13:44





    Oh, sorry, I hadn’t seen this answer before posting mine (I did not refresh the page).

    – GuM
    Apr 9 '16 at 13:44













    @GustavoMezzetti: No worries, you provided a different answer

    – user31729
    Apr 9 '16 at 14:28





    @GustavoMezzetti: No worries, you provided a different answer

    – user31729
    Apr 9 '16 at 14:28











    1














    If you are using environ package then you can write something like this:



    NewEnviron{LHZZ}[1]{%
    expandaftergdefcsname LH#1expandafterendcsname
    expandafter##expandafter1expandafter{BODY}}


    Note, that the code is much more compact than the usage of eTeX's unexpanded, four hashes, etc...






    share|improve this answer




























      1














      If you are using environ package then you can write something like this:



      NewEnviron{LHZZ}[1]{%
      expandaftergdefcsname LH#1expandafterendcsname
      expandafter##expandafter1expandafter{BODY}}


      Note, that the code is much more compact than the usage of eTeX's unexpanded, four hashes, etc...






      share|improve this answer


























        1












        1








        1







        If you are using environ package then you can write something like this:



        NewEnviron{LHZZ}[1]{%
        expandaftergdefcsname LH#1expandafterendcsname
        expandafter##expandafter1expandafter{BODY}}


        Note, that the code is much more compact than the usage of eTeX's unexpanded, four hashes, etc...






        share|improve this answer













        If you are using environ package then you can write something like this:



        NewEnviron{LHZZ}[1]{%
        expandaftergdefcsname LH#1expandafterendcsname
        expandafter##expandafter1expandafter{BODY}}


        Note, that the code is much more compact than the usage of eTeX's unexpanded, four hashes, etc...







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Apr 10 '16 at 20:48









        wipetwipet

        35.3k4983




        35.3k4983






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f303354%2fuse-newcommand-in-newenvironment-content-of-environment-is-argument-of-newc%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

            ComboBox Display Member on multiple fields

            Is it possible to collect Nectar points via Trainline?