[latex3-commits] [git/LaTeX3-latex3-latex2e] gh239: First implementation of \LetRobustCommand (9aa1c9ca)
PhelypeOleinik
tex.phelype at gmail.com
Mon May 4 13:59:02 CEST 2020
Repository : https://github.com/latex3/latex2e
On branch : gh239
Link : https://github.com/latex3/latex2e/commit/9aa1c9ca488c022f9441f789e9737fac5f726494
>---------------------------------------------------------------
commit 9aa1c9ca488c022f9441f789e9737fac5f726494
Author: PhelypeOleinik <tex.phelype at gmail.com>
Date: Mon May 4 08:59:02 2020 -0300
First implementation of \LetRobustCommand
This implementation is a copy of Heiko's \LetLtxMacro with slight modifications thanks to e-TeX.
>---------------------------------------------------------------
9aa1c9ca488c022f9441f789e9737fac5f726494
base/ltdefns.dtx | 224 ++++++++++++++++++++-
base/testfiles/github-0239.lvt | 50 +++++
base/testfiles/github-0239.tlg | 29 +++
.../tlb-latexrelease-rollback-003-often.luatex.tlg | 4 +
.../tlb-latexrelease-rollback-003-often.tlg | 4 +
.../tlb-latexrelease-rollback-003-often.xetex.tlg | 4 +
base/testfiles/tlb-rollback-004-often.luatex.tlg | 2 +
base/testfiles/tlb-rollback-004-often.tlg | 2 +
base/testfiles/tlb-rollback-004-often.xetex.tlg | 2 +
9 files changed, 319 insertions(+), 2 deletions(-)
diff --git a/base/ltdefns.dtx b/base/ltdefns.dtx
index 303b9e56..53d1c444 100644
--- a/base/ltdefns.dtx
+++ b/base/ltdefns.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltdefns.dtx}
- [2020/02/27 v1.5g LaTeX Kernel (definition commands)]
+ [2020/02/27 v1.5h LaTeX Kernel (definition commands)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltdefns.dtx}
@@ -1261,8 +1261,228 @@
% \end{macro}
%
%
+% \begin{macro}{\LetRobustCommand}
+% \changes{v1.5h}{2020/05/01}{Added macro (gh/239)}
+%
+% With most document level commands being robust now there is more of a
+% requirement to have a standard way of aliasing (or copying) a command to a
+% new name, for example to save an original definition before changing a
+% command. \cs{LetRobustCommand} is analogous to \TeX's \cs{let}, except that
+% it copes with the different types of robust commands defined by \LaTeX's
+% mechanisms.
+%
+% The current implementation is an almost exact copy of Heiko Oberdiek's
+% \cs{LetLtxMacro}, with changed names and some simplifications thanks to
+% $\epsilon$-\TeX.
+% \begin{macrocode}
+%</2ekernel>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\LetRobustCommand}{\LetRobustCommand}%
+%<*2ekernel|latexrelease>
+% \end{macrocode}
+% \cs{LetRobustCommand} just calls \cs{let at robustcommand} with a \cs{relax}
+% which serves as a prefix for definitions. Heiko's \pkg{letltxmacro} defines
+% a global variant of \cs{LetLtxMacro}, but since none of our definition
+% commands have a global version, this one won't either, for consistency.
+% \begin{macrocode}
+\def\LetRobustCommand{\let at robustcommand\relax}
+% \end{macrocode}
+% Start by saving the current value of \cs{escapechar} and setting it to $-1$.
+% \begin{macrocode}
+\def\let at robustcommand#1#2#3{%
+ \edef\reserved at a{\the\escapechar}%
+ \escapechar=-1 %
+% \end{macrocode}
+% First we do some normalisation, to cover the case where \verb=#3= expands to
+% \verb*=\protect\#3 =. This is the case when \verb=#3= is a multi-letter
+% control sequence defined with \cs{DeclareRobustCommand}. In this case we
+% copy \verb*=\#3 = into \verb*=\#2 = and then call the inner
+% \cs{let at robust@command} with \verb*=\#2 = and \verb*=\#3 = rather than
+% \verb*=\#2= and \verb*=\#3=.
+% \begin{macrocode}
+ \edef\reserved at b{%
+ \noexpand\protect
+ \expandafter\noexpand\csname\string#3 \endcsname
+ }%
+ \ifx\reserved at b#3\relax
+ #1\edef#2{%
+ \noexpand\protect
+ \expandafter\noexpand
+ \csname\string#2 \endcsname
+ }%
+ #1\expandafter\let
+ \csname\string#2 \expandafter\endcsname
+ \csname\string#3 \endcsname
+ \expandafter\let at robust@command
+ \csname\string#2 \expandafter\endcsname
+ \csname\string#3 \endcsname{#1}%
+% \end{macrocode}
+% Otherwise just call \cs{let at robust@command} with \verb*=\#2= and \verb*=\#3=
+% to do the heavy-lifting.
+% \begin{macrocode}
+ \else
+ \let at robust@command{#2}{#3}{#1}%
+ \fi
+% \end{macrocode}
+% Reset \cs{escapechar} when we're done.
+% \begin{macrocode}
+ \escapechar=\reserved at a\relax
+}
+% \end{macrocode}
+% Check if the \verb=#2= is actually a macro, otherwise just use \cs{let}.
+% \begin{macrocode}
+\def\let at robust@command#1#2#3{%
+ \escapechar=92 %
+ \expandafter\let at robust@chk at parm\meaning#2:->\@nil{%
+% \end{macrocode}
+% Now the real fun begins. We'll redefine (in a group) some of \LaTeX's
+% optional argument-processing macros because TODO
+% Also make \cs{let at robust@testopt} equal to \cs{@empty} to signal no optional
+% argument (may change).
+% \begin{macrocode}
+ \begingroup
+ \def\@protected at testopt{%
+ \expandafter\@testopt\@gobble}%
+ \def\@testopt##1##2{%
+ \toks@={##2}}%
+ \let\let at robust@testopt\@empty
+% \end{macrocode}
+% Define \cs{reserved at c} as \verb=\@protected at testopt\#2\\#2=\ldots
+% \begin{macrocode}
+ \edef\reserved at c{%
+ \noexpand\@protected at testopt
+ \noexpand#2%
+ \expandafter\noexpand\csname\string#2\endcsname
+ }%
+% \end{macrocode}
+% and define \cs{reserved at d} as the first three (or fewer) tokens in the
+% expansion of \verb=#2=\ldots
+% \begin{macrocode}
+ \edef\reserved at d{%
+ \unexpanded\expandafter\expandafter\expandafter
+ {\expandafter\let at robust@CarThree#2{}{}{}\@nil}}
+% \end{macrocode}
+% then compare both. If they are equal, the macro contains a test for an
+% optional argument, in which case \verb=#2= is executed, so that the default
+% value of the optional argument is stored in \cs{toks@} and
+% \cs{let at robust@testopt} is redefined accordingly.
+% \begin{macrocode}
+ \ifx\reserved at c\reserved at d
+ #2%
+ \def\let at robust@testopt{%
+ \noexpand\@protected at testopt
+ \noexpand#1%
+ }%
+% \end{macrocode}
+% Otherwise we try again and redefine \cs{reserved at c} as
+% \verb=\@testopt\\#2=\ldots
+% \begin{macrocode}
+ \else
+ \edef\reserved at c{%
+ \noexpand\@testopt
+ \expandafter\noexpand
+ \csname\string#2\endcsname
+ }%
+% \end{macrocode}
+% and \cs{reserved at d} as the first two (or fewer) tokens in the expansion of
+% \verb=#2=. Now if they are equal, execute \verb=#2= so that the default
+% value of the optional argument of \verb=#2= is stored in \cs{toks@}, and
+% then reassign \cs{let at robust@testopt} to be \cs{@testopt}.
+% \begin{macrocode}
+ \edef\reserved at d{%
+ \unexpanded\expandafter\expandafter\expandafter
+ {\expandafter\let at robust@CarTwo#2{}{}{}\@nil}}
+ \ifx\reserved at c\reserved at d
+ #2%
+ \def\let at robust@testopt{%
+ \noexpand\@testopt
+ }%
+ \fi
+ \fi
+% \end{macrocode}
+% Now, unless \cs{let at robust@testopt} is empty (that is, no optional argument)
+% define \cs{let at robust@GlobalTemp} to be
+% \meta{testopt}\cs{\#1}\{\meta{opt-default}\}, where
+% \meta{testopt} is either \verb=\@protected at testopt\#2=, or \verb=\@testopt=.
+% \begin{macrocode}
+ \ifx\let at robust@testopt\@empty
+ \else
+ \let at robust@protected\xdef\let at robust@GlobalTemp{%
+ \let at robust@testopt
+ \expandafter\noexpand
+ \csname\string#1\endcsname
+ {\the\toks@}%
+ }%
+ \fi
+% \end{macrocode}
+% We're almost done now. If \cs{let at robust@testopt} remained empty all along,
+% then the macro didn't have an optional argument and we just need to \cs{let}
+% one to the other.
+% Otherwise we \cs{let} \verb=\#1=, the top-level macro, to
+% \cs{let at robust@GlobalTemp}, and then \cs{let} \verb=\\#1= to \verb=\\#2=,
+% which is the actual definition of the macro.
+% \begin{macrocode}
+ \expandafter\endgroup\ifx\let at robust@testopt\@empty
+ #3\let#1=#2\relax
+ \else
+ #3\let#1=\let at robust@GlobalTemp
+ #3\expandafter\let
+ \csname\string#1\expandafter\endcsname
+ \csname\string#2\endcsname
+ \fi
+ }{%
+ #3\let#1=#2\relax
+ }%
+}
+% \end{macrocode}
+% This auxiliary detects whether the argument is a macro (otherwise this
+% entire process boils down to \TeX's \cs{let}), and in case of a
+% \cs{protected} macro (using \pkg{etoolbox}'s \cs{newrobustcmd}), define
+% \cs{let at robust@protected} accordingly.
+% \begin{macrocode}
+\def\let at robust@chk at parm#1:->#2\@nil{%
+ \tmp at strifeq{#1}{macro}%
+ {%
+ \def\let at robust@protected{}%
+ \@firstoftwo
+ }{%
+ \tmp at strifeq{#1}{\protected macro}%
+ {%
+ \def\let at robust@protected{\protected}%
+ \@firstoftwo%
+ }
+ {\@secondoftwo}%
+ }%
+}
+% \end{macrocode}
+% This is just a temporary poor-man's string comparison macro to make things
+% easier. This should be replaced by \cs{@expl at str@if at eq@nnTF} once that's
+% defined.
+% \begin{macrocode}
+\def\tmp at strifeq#1#2{%
+ \begingroup
+ \edef\reserved at a{\detokenize{#1}}%
+ \edef\reserved at b{\detokenize{#2}}%
+ \expandafter\endgroup
+ \ifx\reserved at a\reserved at b
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi}
+% \end{macrocode}
+% Takes the first two or three tokens of the argument.
+% \begin{macrocode}
+\def\let at robust@CarTwo#1#2#3\@nil{#1#2}%
+\def\let at robust@CarThree#1#2#3#4\@nil{#1#2#3}%
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}{\LetRobustCommand}{\LetRobustCommand}%
+%<latexrelease>\let\LetRobustCommand\@undefined
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
+% \end{macrocode}
+% \end{macro}
+%
%
-
% \begin{macro}{\kernel at make@fragile}
% The opposite of |\MakeRobust| execpt that it doesn't do many
% checks as it is internal to the kernel. Why does one want such a
diff --git a/base/testfiles/github-0239.lvt b/base/testfiles/github-0239.lvt
new file mode 100644
index 00000000..ef43b8b7
--- /dev/null
+++ b/base/testfiles/github-0239.lvt
@@ -0,0 +1,50 @@
+
+\documentclass{article}
+\input{test2e}
+
+\showoutput
+
+\begin{document}
+
+\START
+
+\def\testt#1#2#3#4{%
+ #4%
+ \LetRobustCommand#1#3%
+ \testtt#1
+ \expandafter\testtt\csname#2\space\endcsname
+ \expandafter\testtt\csname\string#1\endcsname
+ \expandafter\testtt\csname\string#1\space\endcsname
+ \typeout{}}
+\def\testtt#1{%
+ \typeout{\string#1=\meaning#1|}%
+ \let#1\undefined}
+
+% Here we need control words
+\def\test{\testt\tmp{tmp}}
+
+\test\cmda{\newcommand\cmda[1][]{boo}}
+
+\test\cmdb{\DeclareRobustCommand\cmdb[1]{boo}}
+
+\test\cmdc{\DeclareRobustCommand\cmdc[1][]{boo}}
+
+% \test\cmdd{\newrobustcmd\cmdd[1]{boo}}
+
+% \test\cmde{\newrobustcmd\cmde[1][]{boo}}
+
+% And here control symbols
+\def\test{\testt\+{+}}
+
+\test\!{\renewcommand\![1][]{boo}}
+
+\test\@{\DeclareRobustCommand\@[1]{boo}}
+
+\test\#{\DeclareRobustCommand\#[1][]{boo}}
+
+% \test\${\renewrobustcmd\$[1]{boo}}
+
+% \test\&{\renewrobustcmd\&[1][]{boo}}
+
+\end{document}
+
diff --git a/base/testfiles/github-0239.tlg b/base/testfiles/github-0239.tlg
new file mode 100644
index 00000000..43bcd13c
--- /dev/null
+++ b/base/testfiles/github-0239.tlg
@@ -0,0 +1,29 @@
+This is a generated file for the LaTeX2e validation system.
+Don't change this file in any respect.
+\tmp=macro:->\@protected at testopt \tmp \\tmp {}|
+\tmp =\relax|
+\\tmp=\long macro:[#1]->boo|
+\\tmp =\relax|
+\tmp=macro:->\protect \tmp |
+\tmp =\long macro:#1->boo|
+\\tmp=\relax|
+\\tmp =\relax|
+\tmp=macro:->\protect \tmp |
+\tmp =macro:->\@protected at testopt \tmp \\tmp {}|
+\\tmp=\relax|
+\\tmp =\long macro:[#1]->boo|
+\+=macro:->\@protected at testopt \+\\+ {}|
+\+ =\relax|
+\\+=\long macro:[#1]->boo|
+\\+ =\relax|
+LaTeX Info: Redefining \@ on input line ....
+\+=macro:->\protect \+ |
+\+ =\long macro:#1->boo|
+\\+=\relax|
+\\+ =\relax|
+LaTeX Info: Redefining \# on input line ....
+\+=macro:->\x at protect \#\protect \# |
+\+ =\relax|
+\\+=\relax|
+\\+ =\relax|
+(github-0239.aux)
diff --git a/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg b/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg
index 91f7a347..8f09d413 100644
--- a/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg
+++ b/base/testfiles/tlb-latexrelease-rollback-003-often.luatex.tlg
@@ -13,6 +13,8 @@ Applying: [....-..-..] Final dot for extension on input line ....
Skipping: [....-..-..] \MakeRobust on input line ....
Skipping: [....-..-..] \MakeRobust on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Skipping: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
@@ -322,6 +324,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Already applied: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
diff --git a/base/testfiles/tlb-latexrelease-rollback-003-often.tlg b/base/testfiles/tlb-latexrelease-rollback-003-often.tlg
index 4ff8aad5..cf9bedf3 100644
--- a/base/testfiles/tlb-latexrelease-rollback-003-often.tlg
+++ b/base/testfiles/tlb-latexrelease-rollback-003-often.tlg
@@ -11,6 +11,8 @@ Applying: [....-..-..] Final dot for extension on input line ....
Skipping: [....-..-..] \MakeRobust on input line ....
Skipping: [....-..-..] \MakeRobust on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Skipping: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
@@ -314,6 +316,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Already applied: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
diff --git a/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg b/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg
index daf145e1..b864a35b 100644
--- a/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg
+++ b/base/testfiles/tlb-latexrelease-rollback-003-often.xetex.tlg
@@ -11,6 +11,8 @@ Applying: [....-..-..] Final dot for extension on input line ....
Skipping: [....-..-..] \MakeRobust on input line ....
Skipping: [....-..-..] \MakeRobust on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Skipping: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
@@ -323,6 +325,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Already applied: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
diff --git a/base/testfiles/tlb-rollback-004-often.luatex.tlg b/base/testfiles/tlb-rollback-004-often.luatex.tlg
index 5fa4be2a..a6b3cafe 100644
--- a/base/testfiles/tlb-rollback-004-often.luatex.tlg
+++ b/base/testfiles/tlb-rollback-004-often.luatex.tlg
@@ -10,6 +10,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Already applied: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
diff --git a/base/testfiles/tlb-rollback-004-often.tlg b/base/testfiles/tlb-rollback-004-often.tlg
index 923188b8..586d0c31 100644
--- a/base/testfiles/tlb-rollback-004-often.tlg
+++ b/base/testfiles/tlb-rollback-004-often.tlg
@@ -8,6 +8,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Already applied: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
diff --git a/base/testfiles/tlb-rollback-004-often.xetex.tlg b/base/testfiles/tlb-rollback-004-often.xetex.tlg
index 52063867..f37c5333 100644
--- a/base/testfiles/tlb-rollback-004-often.xetex.tlg
+++ b/base/testfiles/tlb-rollback-004-often.xetex.tlg
@@ -8,6 +8,8 @@ Already applied: [....-..-..] Final dot for extension on input line ....
Applying: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
Already applied: [....-..-..] \MakeRobust on input line ....
+Skipping: [....-..-..] \LetRobustCommand on input line ....
+Applying: [....-..-..] \LetRobustCommand on input line ....
Applying: [....-..-..] Undo robustness on input line ....
Applying: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
Already applied: [....-..-..] Leave commands undefined in \@ifundefined on input line ....
More information about the latex3-commits
mailing list.