Off the cuff I can only offer a macro \ReplacementScope
which takes two arguments:
The first argument is a comma-separated list of ⟨tokens to replace⟩=⟨replacement⟩
-pairs.
The second argument is a ⟨brace balanced list of tokens⟩
.
Within ⟨brace balanced list of tokens⟩
each instance of ⟨tokens to replace⟩
will be replaced by ⟨replacement⟩
for each ⟨tokens to replace⟩=⟨replacement⟩
-pair.
!!! Use with caution !!!
\ReplacementScope
as a side-effect also replaces all pairs of matching explicit character tokens of catcode 1(begin group)/2(end group) by matching curly braces {1(begin group)
/ }2(end group)
!!!
⟨tokens to replace⟩
must not contain explicit character tokens of catcode 1(begin group) or 2(end group)!!!
⟨tokens to replace⟩
must not contain tokens of catcode 6(parameter)!!!
- Defines temporary macros, therefore not fully expandable!!!
- You need to take care of correct order in which replacements shall take place!!!
You can use \ReplacementScope
for replacing text-strings, e.g., by #1
or by #2
or by ##1
or whatever.
Ad item 1:
Under normal catcode-régime the only character of catcode 1 is the curly left brace and the only character of catcode 2 is the curly right brace. So under normal catcode-régime the replacement of character tokens of catcode 1/2 by matching curly braces does not yield a difference. Even if things got tokenized under unusual catcode-régime, the replacement usually doesn't matter. But there are edge cases.
E.g., if you have assigned catcode 1 to the character X
, you can use X
like {
and, e.g., do:
\def\tempaXdefinition of tempa}%
.
This will be tokenized as:
\def
, \tempa
, X1
, d11
, e11
, f11
, i11
, n11
, i11
, t11
, i11
, o11
, n11
, ⟨space⟩10
, o11
, f11
, ⟨space⟩10
, t11
, e11
, m11
, p11
, a11
, }2
.
If this is done within \ReplacementScope
, then this will be turned to
\def
, \tempa
, {1
, d11
, e11
, f11
, i11
, n11
, i11
, t11
, i11
, o11
, n11
, ⟨space⟩10
, o11
, f11
, ⟨space⟩10
, t11
, e11
, m11
, p11
, a11
, }2
.
At first glimpse this doesn't matter.
Assume you wish for some obscure reason to apply #{
-notation for defining a macro \tempa
whose argument is delimited by an explicit X-character-token of category-code 1(begin group) which will be left in place.
You would do:
\catcode`\X=1
\def\tempa#1#Xdefinition of tempa}%
The second line would be tokenized as:
\def
, \tempa
, #6
, 112
, #6
, X1
, d11
, e11
, f11
, i11
, n11
, i11
, t11
, i11
, o11
, n11
, ⟨space⟩10
, o11
, f11
, ⟨space⟩10
, t11
, e11
, m11
, p11
, a11
, }2
.
Inside \ReplacementScope
this will be turned into:
\def
, \tempa
, #6
, 112
, #6
, {1
, d11
, e11
, f11
, i11
, n11
, i11
, t11
, i11
, o11
, n11
, ⟨space⟩10
, o11
, f11
, ⟨space⟩10
, t11
, e11
, m11
, p11
, a11
, }2
.
This makes a difference:
Instead of being delimited by X1(begin group)
the argument of \tempa
will be delimited by {1(begin group)
and this affects the delimiter-matching.
Ad item 5:
The order in which replacements occur makes a difference:
E.g.,
\ReplacementScope{VARIABLEA=#1, INNERVARIABLEA=##1}{%
\newcommand\Outside[1]{%
\newcommand\Inside[1]{%
VARIABLEA and INNERVARIABLEA
}%
}%
}%
yields
\newcommand\Outside[1]{%
\newcommand\Inside[1]{%
#1 and INNER#1
}%
}%
whereas
\ReplacementScope{INNERVARIABLEA=##1, VARIABLEA=#1}{%
\newcommand\Outside[1]{%
\newcommand\Inside[1]{%
VARIABLEA and INNERVARIABLEA
}%
}%
}%
yields
\newcommand\Outside[1]{%
\newcommand\Inside[1]{%
#1 and ##1
}%
}%
I think as long as you don't do intriguing plain-TeX-\def\macro#1#⟨non-brace-character of catcode 1⟩
-trickery you will be pretty safe.
Nevertheless I am not really a fan of such things:
First, you get one more level of processing which you have to take into account when tracking bugs.
Second, I see here an attempt to transfer things to TeX that are related to programming paradigms other than those given in TeX. In my experience, such undertakings are very susceptible to difficulties that can only be solved if you are very familiar with the programming paradigms of TeX. But if you are, then you can do without such transfers from other areas of programming.
Third, probably the replacement-task can be performed by the editor/by the software in use for writing the .tex-file.
Fourth, probably LuaTeX-based TeX-engines are more suitable for this kind of undertaking.
\documentclass[a4paper]{article}
\makeatletter
%%//////////////////////// Code of \ReplacementScope: /////////////////////////
%%=============================================================================
\RequirePackage{pgfkeys}%
\pgfkeys{%
/ReplacementScope/.unknown/.code=%
\expandafter\UD@AddToReplacementlist\expandafter{\pgfkeyscurrentname}{#1},%
}%
\newcommand*\UD@Replacementlist{}%
\newcommand\UD@AddToReplacementlist[2]{%
\expandafter\UD@Exchange
\expandafter{\expandafter\toks@\expandafter{\the\toks@}}{%
\toks@{\UD@Revert{#1}{#2}}%
\ifx\UD@Replacementlist\empty
\toks@\expandafter{\the\toks@{\endgroup\@firstofone}}%
\else
\toks@\expandafter{%
\the\expandafter\toks@\expandafter{\UD@Replacementlist}%
}%
\fi
\edef\UD@Replacementlist{\the\toks@}%
}%
}%
\newcommand\UD@Revert[4]{%
#3{\UD@Replace{#1}{#2}{#4}}%
}%
\newcommand\ReplacementScope[1]{%
\begingroup
\pgfkeys{/ReplacementScope/.cd,#1,}%
\ifx\UD@Replacementlist\empty\endgroup\expandafter\@secondoftwo\fi
\UD@Replacementlist{\@firstofone}%
}%
%%=============================================================================
%%//////////////////// End of code of \ReplacementScope: //////////////////////
%%
%%//////////////////// Code of my own replacement-routine: ////////////////////
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo,
%% \UD@PassFirstToSecond, \UD@Exchange, \UD@removespace
%% \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%% \UD@CheckWhetherLeadingTokens, \UD@ExtractFirstArg
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%-----------------------------------------------------------------------------
%% 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\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\z@\UD@secondoftwo}%
{\expandafter\z@\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
\romannumeral\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\z@\UD@firstoftwo}%
{\expandafter\z@\UD@secondoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific
%% token-sequence that does neither contain explicit character tokens of
%% category code 1 or 2 nor contain tokens of category code 6:
%%.............................................................................
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%% {<a <token sequence> without explicit
%% character tokens of category code
%% 1 or 2 and without tokens of
%% category code 6>}%
%% {<internal token-check-macro>}%
%% {<tokens to be delivered in case
%% <argument which is to be checked> has
%% <token sequence> as leading tokens>}%
%% {<tokens to be delivered in case
%% <argument which is to be checked>
%% does not have <token sequence> as
%% leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[3]{%
\romannumeral\UD@CheckWhetherNull{#1}{\expandafter\z@\UD@secondoftwo}{%
\expandafter\UD@secondoftwo\string{\expandafter
\UD@@CheckWhetherLeadingTokens#3{\relax}#1#2}{}}%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\z@\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%% {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[2]{%
\@ifdefinable#1{\long\def#1##1#2{{##1}}}%
}%
\UD@internaltokencheckdefiner{\UD@InternalExplicitSpaceCheckMacro}{ }%
%%-----------------------------------------------------------------------------
%% Extract first inner undelimited argument:
%%
%% \romannumeral\UD@ExtractFirstArgLoop{ABCDE\UD@SelDOm} yields {A}
%%
%% \romannumeral\UD@ExtractFirstArgLoop{{AB}CDE\UD@SelDOm} yields {AB}
%%.............................................................................
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\z@#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%%=============================================================================
%% \UD@Replace{<token-sequence to replace>}%
%% {<replacement>}%
%% {<tokens afterwards>}
%% {<token list>}
%%
%% Replaces all instances of <token-sequence to replace> in <token list>
%% by <replacement>. The result will be nested in curly braces and
%% preceeded by <tokens afterwards>.
%%
%% !!! Does also replace all pairs of matching explicit character tokens of
%% catcode 1/2 by matching braces!!!
%% !!! <token-sequence to replace> must not contain explicit character tokens
%% of catcode 1 or 2 !!!
%% !!! <token-sequence to replace> must not contain tokens of catcode 6 !!!
%% !!! Defines temporary macro \UD@temp, therefore not expandable !!!
%%-----------------------------------------------------------------------------
\newcommand\UD@Replace[4]{%
% #1 - <token-sequence to replace>
% #2 - <replacement>
% #3 - <tokens afterwards>
% #4 - <token list>
\begingroup
\UD@internaltokencheckdefiner{\UD@temp}{#1}%
\expandafter\endgroup
\romannumeral\UD@ReplaceLoop{#4}{}{#1}{#2}{#3}%
}%
\newcommand\UD@ReplaceLoop[5]{%
% Do:
% \UD@internaltokencheckdefiner{\UD@temp}{<token-sequence to replace>}%
% \romannumeral\UD@ReplaceLoop{<token list>}%
% {<sequence created so far, initially empty>}%
% {<token-sequence to replace>}%
% {<replacement>}%
% {<tokens afterwards>}%
%
% #1 - <token list>
% #2 - <sequence created so far, initially empty>
% #3 - <token-sequence to replace>
% #4 - <replacement>
% #5 - <tokens afterwards>
\UD@CheckWhetherNull{#1}{\z@#5{#2}}{%
\UD@CheckWhetherLeadingTokens{#1}{#3}{\UD@temp}{%
\expandafter\expandafter\expandafter\UD@ReplaceLoop
\expandafter\expandafter\expandafter{%
\expandafter\UD@firstoftwo\expandafter{\expandafter}\UD@temp#1%
}{#2#4}%
}{%
\UD@CheckWhetherLeadingTokens{#1}{ }{\UD@InternalExplicitSpaceCheckMacro}{%
\expandafter\UD@ReplaceLoop
\expandafter{\UD@removespace#1}{#2 }%
}{%
\UD@CheckWhetherBrace{#1}{%
\expandafter\expandafter\expandafter\UD@PassFirstToSecond
\expandafter\expandafter\expandafter{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral\expandafter\expandafter\expandafter\z@
\romannumeral\expandafter\UD@ReplaceLoop
\romannumeral
\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{}{#3}{#4}{\@firstofone}%
}{#2}}%
{\expandafter\UD@ReplaceLoop\expandafter{\UD@firstoftwo{}#1}}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{%
\romannumeral
\expandafter\UD@Exchange
\romannumeral\UD@ExtractFirstArgLoop{#1\UD@SelDOm}{\z@#2}%
}{\expandafter\UD@ReplaceLoop\expandafter{\UD@firstoftwo{}#1}}%
}%
}%
}%
{#3}{#4}{#5}%
}%
}%
\makeatother
%%=============================================================================
%%///////////////// End of code of my own replacement-routine. ////////////////
\makeatother
\ReplacementScope{VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\myfirstcommand}[3]{%
Argument 1 is VAR_A.\\
Argument 2 is VAR_B.\\
Argument 3 is VAR_C.
}%
%
}
\ReplacementScope{}{%
%
\newcommand{\mysecondcommand}[3]{%
Three arguments are gobbled.
This sentence contains the string VAR_A.\\
This sentence contains the string VAR_B.\\
This sentence contains the string VAR_C.\\
}%
%
}
\ReplacementScope{INNERVAR_A=##1, INNERVAR_B=##2, INNERVAR_C=##3, VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\mythirdcommand}[3]{%
\newcommand{\myinnerthirdcommand}[3]{%
Argument 1 is INNERVAR_A.\\
Argument 2 is INNERVAR_B.\\
Argument 3 is INNERVAR_C.
}%
\myinnerthirdcommand{VAR_A}{VAR_B}{VAR_C}%
}%
%
}
\usepackage{tikz}
\usepackage{pgfplots}
\ReplacementScope{MYVALUE=#1}{%
%
\newcommand{\mydraw}[1]{%
\addplot [mark=*] coordinates{(MYVALUE,0.3)};
\draw node at (axis cs:MYVALUE,0.4) [below] {MYVALUE};
}%
%
}%
\begin{document}
\begingroup
\ttfamily\footnotesize
\begin{verbatim}
\ReplacementScope{VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\myfirstcommand}[3]{%
Argument 1 is VAR_A.\\
Argument 2 is VAR_B.\\
Argument 3 is VAR_C.
}%
%
}
\end{verbatim}
\string\myfirstcommand=\meaning\myfirstcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope{}{%
%
\newcommand{\mysecondcommand}[3]{%
Three arguments are gobbled.
This sentence contains the string VAR_A.\\
This sentence contains the string VAR_B.\\
This sentence contains the string VAR_C.\\
}%
%
}
\end{verbatim}
\string\mysecondcommand=\meaning\mysecondcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope{INNERVAR_A=##1, INNERVAR_B=##2, INNERVAR_C=##3, VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\mythirdcommand}[3]{%
\newcommand{\myinnerthirdcommand}[3]{%
Argument 1 is INNERVAR_A.\\
Argument 2 is INNERVAR_B.\\
Argument 3 is INNERVAR_C.
}%
\myinnerthirdcommand{VAR_A}{VAR_B}{VAR_C}%
}%
%
}
\end{verbatim}
\string\mythirdcommand=\meaning\mythirdcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope{MYVALUE=#1}{%
%
\newcommand{\mydraw}[1]{%
\addplot [mark=*] coordinates{(MYVALUE,0.3)};
\draw node at (axis cs:MYVALUE,0.4) [below] {MYVALUE};
}%
%
}%
\end{verbatim}
\string\mydraw=\meaning\mydraw
\vfill\hrule\vfill\vfill
\endgroup
\newpage
\begin{tikzpicture}
\begin{axis}
\addplot coordinates{(0,0) (1,1)};
\mydraw{0.4}
\mydraw{0.6}
\end{axis}
\end{tikzpicture}
\end{document}


Edit in November 17, 2020:
It just came to my mind that with another approach you get rid of the restrictions mentioned in items 1 - 4:
Have \ReplacementScope
read its arguments under verbatim-catcode-régime, e.g., v/+v
-type of xparse, put the ⟨brace balanced list of tokens⟩
into an expl3-token-list-variable and iterate the comma-separated list of ⟨tokens to replace⟩=⟨replacement⟩
-pairs via \keyval_parse:NNn
for recursively calling expl3's \tl_replace_all:Nnn ⟨tl var⟩ {⟨old tokens⟩} {⟨new tokens⟩}
-function and then pass the result to \tex_scantokens:D
for re-tokenization and re-digestion—the code for this is considerably shorter than the code in my other approach, and you don't need \makeatletter..\makeatother
:
Shortcomings:
Due to replacement-directives being in terms of a comma-separated ⟨tokens to replace⟩=⟨replacement⟩
-list
\ReplacementScope
cannot be used for replacing (with) phrases that contain at least one comma.
\ReplacementScope
cannot be used for replacing (with) phrases that have leading and/or trailing spaces.
As \ReplacementScope
processes arguments that are to be read and tokenized under verbatim-catcode-régime, the same restrictions apply as with the command \verb
.
\documentclass[a4paper]{article}
%%//////////////////////// Code of \ReplacementScope: /////////////////////////
%%=============================================================================
\RequirePackage{xparse}%
\NewDocumentCommand\ReplacementScope{}{%
\begingroup
% Catcode of horizontal tab is not switched to 12(other) by xparse's
% routine for reading v/+v-type-arguments, so let's do that now:
\catcode`\^^I=12\relax
\InnerReplacementScope
}%
\ExplSyntaxOn
\msg_new:nnnn{ReplacementScope}%
{NoValueError}%
{Line\ #2\ specifies\ to\ replace\ the\ phrase:\\#1\\But\ a\ replacement\ text\ is\ not\ specified.}
{If\ you\ want\ to\ replace\ things,\ then\ you\ need\ to\ specify\ both\ the\ phrase\ to\ replace\ and\ the\ replacement\ text.}
\cs_new:Nn \ReplacementScope_NovalueError:n {
\group_begin:
\cs_set:Nn \msg_error_text:n {##1~Error:}
\msg_error:nnxx {ReplacementScope}{NoValueError}{#1}{\msg_line_number:}
\group_end:
}
\cs_new:Nn \ReplacementScope_Replace:nn {
\tl_replace_all:Nnn \l_tmpa_tl {#1}{#2}
}
\group_begin:
\char_set_catcode_other:N \^^M
\use:n{
\group_end:
\NewDocumentCommand\InnerReplacementScope{+v+v}{
\group_end:\group_begin:
\tl_set:Nn \l_tmpa_tl {#2}
\keyval_parse:NNn \ReplacementScope_NovalueError:n \ReplacementScope_Replace:nn { #1 }
\exp_args:Nnc \use:n { \exp_args:Nno \tl_put_right:Nn { \l_tmpa_tl } } {@percentchar}
\exp_args:Nno \tl_put_left:Nn {\l_tmpa_tl} {\token_to_str:N \endgroup ^^M}
% \tl_show:N \l_tmpa_tl
\tex_newlinechar:D=\tex_endlinechar:D
\exp_args:NV \tex_scantokens:D {\l_tmpa_tl}
}
}
\ExplSyntaxOff
%%=============================================================================
%%//////////////////// End of code of \ReplacementScope: //////////////////////
\ReplacementScope{VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\myfirstcommand}[3]{%
Argument 1 is VAR_A.\\
Argument 2 is VAR_B.\\
Argument 3 is VAR_C.
}%
%
}
\ReplacementScope|}VAR_A}=#1, }VAR_B}=#2, }VAR_C}=#3||%
%
\newcommand{\mysecondcommand}[3]{%
Argument 1 is }VAR_A}.\\
Argument 2 is }VAR_B}.\\
Argument 3 is }VAR_C}.
}%
%
|
\ReplacementScope{}{%
%
\newcommand{\mythirdcommand}[3]{%
Three arguments are gobbled.
This sentence contains the string VAR_A.\\
This sentence contains the string VAR_B.\\
This sentence contains the string VAR_C.\\
}%
%
}
\ReplacementScope{INNERVAR_A=##1, INNERVAR_B=##2, INNERVAR_C=##3, VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\myfourthcommand}[3]{%
\newcommand{\myinnerfourthcommand}[3]{%
Argument 1 is INNERVAR_A.\\
Argument 2 is INNERVAR_B.\\
Argument 3 is INNERVAR_C.
}%
\myinnerfourthcommand{VAR_A}{VAR_B}{VAR_C}%
}%
%
}
\usepackage{tikz}
\usepackage{pgfplots}
\ReplacementScope{MYVALUE=#1}{%
%
\newcommand{\mydraw}[1]{%
\addplot [mark=*] coordinates{(MYVALUE,0.3)};
\draw node at (axis cs:MYVALUE,0.4) [below] {MYVALUE};
}%
%
}%
\begin{document}
\begingroup
\advance\oddsidemargin -.75in\relax
\advance\textwidth 1.5in\relax
\advance\linewidth 1.5in\relax
\advance\hsize 1.5in\relax
\null\kern-1.7in \enlargethispage{.3in}%
\sloppy
\ttfamily\footnotesize\frenchspacing
\parindent=0ex
\begin{verbatim}
\ReplacementScope{VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\myfirstcommand}[3]{%
Argument 1 is VAR_A.\\
Argument 2 is VAR_B.\\
Argument 3 is VAR_C.
}%
%
}
\end{verbatim}
\string\myfirstcommand=\meaning\myfirstcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope|}VAR_A}=#1, }VAR_B}=#2, }VAR_C}=#3||%
%
\newcommand{\mysecondcommand}[3]{%
Argument 1 is }VAR_A}.\\
Argument 2 is }VAR_B}.\\
Argument 3 is }VAR_C}.
}%
%
|
\end{verbatim}
\string\mysecondcommand=\meaning\mysecondcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope{}{%
%
\newcommand{\mythirdcommand}[3]{%
Three arguments are gobbled.
This sentence contains the string VAR_A.\\
This sentence contains the string VAR_B.\\
This sentence contains the string VAR_C.\\
}%
%
}
\end{verbatim}
\string\mythirdcommand=\meaning\mythirdcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope{INNERVAR_A=##1, INNERVAR_B=##2, INNERVAR_C=##3, VAR_A=#1, VAR_B=#2, VAR_C=#3}{%
%
\newcommand{\myfourthcommand}[3]{%
\newcommand{\myinnerfourthcommand}[3]{%
Argument 1 is INNERVAR_A.\\
Argument 2 is INNERVAR_B.\\
Argument 3 is INNERVAR_C.
}%
\myinnerfourthcommand{VAR_A}{VAR_B}{VAR_C}%
}%
%
}
\end{verbatim}
\string\myfourthcommand=\meaning\myfourthcommand
\vfill\hrule\vfill
\begin{verbatim}
\ReplacementScope{MYVALUE=#1}{%
%
\newcommand{\mydraw}[1]{%
\addplot [mark=*] coordinates{(MYVALUE,0.3)};
\draw node at (axis cs:MYVALUE,0.4) [below] {MYVALUE};
}%
%
}%
\end{verbatim}
\string\mydraw=\meaning\mydraw
\vfill\hrule\vfill
\newpage
\endgroup
\begin{tikzpicture}
\begin{axis}
\addplot coordinates{(0,0) (1,1)};
\mydraw{0.4}
\mydraw{0.6}
\end{axis}
\end{tikzpicture}
\end{document}

pgfplots
, but as far as I can see it should work.namedef
will act at the time you define the macro (no named parameters will remain after the definition). After the definition is done, it is indistinguishable if you did or did not usenamedef
. (namedef
scans the definition, replaces the named parameters (#[whatever]
) by numbered ones (#1
), then passes the definition on to TeX do its thing). Try this: pastebin.com/raw/a9pwEvvT