Use \newcommand in \newenvironment - content of environment is argument of \newcommand
The command form is easier:
\documentclass{article}
\newcommand{\LHZZ}[2]{%
\expandafter\newcommand\csname LH#1\endcsname[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]{%
\edef\maestroglanz@temp{%
\unexpanded{\expandafter\gdef\csname LH#1\endcsname}####1{\unexpanded\expandafter{\BODY}}%
}%
\maestroglanz@temp
}
\makeatother
\begin{document}
\begin{LHZZ}{XY}
write stuff here
refer to #1
\end{LHZZ}
\LHXY{parameter}
\end{document}
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}a\end{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}a\end{LHZZ}
\end{document}
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#1\endcsname}[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 \global\edef
(see Christian’s answer; note, however, that \global\edef
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#1\endcsname}[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#1\endcsname}[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 ##1\par % 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{%
\noexpand\newcommand{\csname LH#1\endcsname}[1]{%
\unexpanded\expandafter{\BODY}%
}%
}%
% ... but this one works too (the astersik is there only to illustrate
% another possibility: define a non-"\long" command):
\xdef\@my@temporary@y{%
\noexpand\newcommand*{\csname MG#1\endcsname}[1][default]{%
\unexpanded\expandafter{\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 \meaning\LHXY
\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 defined\else not defined\fi
}.
\end{document}
But I’d better follow @egreg’s solicitation… (see comments ;-)
I think this is code golfing however...
\expandafter\newcommand\csname ....\endcsname{...
won't work outside -- it's a local definition.
\global\expandafter\newcommand...won't work neither due to expansion, but \global\expandafter\def\csname...
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 \expandafter\xdef\csname....
or \global\expandafter\edef\csname...
\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{environ}
\setlength{\parindent}{0pt}
\NewEnviron{LHZZ}[1]{%
\long\global\expandafter\edef\csname LH#1\endcsname##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}