How to properly smuggle (with or even without TikZ)?












23















I am seeking to find something that allows me to "broadcast" macros outside a group. Concrete examples include paths and scopes in tizpictures. Here is an M(N)WE.



documentclass[tikz,border=3.14mm]{standalone}
usetikzlibrary{calc}
makeatletter
letsmuggleoutonepgfmath@smuggleone
makeatother
begin{document}
begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
%smuggleoutone#1
}]
begin{scope}[local bounding box=extra]
path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
pgfextra{xdefmyangle{n1}};
node at (1,0) {myangle};
end{scope}
node[anchor=south] at (extra.north) {using verb|pgfextra|};
%
begin{scope}[local bounding box=globalize,xshift=3cm]
path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
[globalize={n1}{myangle}];
node at (1,0) {myangle};
end{scope}
node[anchor=south] at (globalize.north) {using texttt{globalize}};
%
xdefmyangle{7}
begin{scope}[local bounding box=localize,xshift=6cm]
path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
[localize={n1}{myangle}];
node at (1,0) {myangle};
end{scope}
node[anchor=south] at (localize.north) {attempt to smuggle};
%
end{tikzpicture}
end{document}


enter image description here



The two options on the left do partly what I am seeking to do, namely broadcast the macro myangle outside the path. However, they do it at the expense of making myangle global. TikZ has some internal commands that may allow one to avoid this, and to just smuggle the macro outside the path. Specifically, @DavidCarlisle suggested in the chat to use pgfmath@smuggleone. However, my above attempts failed, i.e. if I uncomment



%smuggleoutone#1


the code produces errors.



QUESTION: Can one smuggle the macro outside the group without making it global?



"BONUS": Of course it would be great if there was an explanation what all the smuggle commands do.



"BONUUUUS": Conceivably these methods may be useful independently of TikZ, so if there is a way not to make them depend on TikZ being loaded, this would be great, but is certainly not a requirement.










share|improve this question





























    23















    I am seeking to find something that allows me to "broadcast" macros outside a group. Concrete examples include paths and scopes in tizpictures. Here is an M(N)WE.



    documentclass[tikz,border=3.14mm]{standalone}
    usetikzlibrary{calc}
    makeatletter
    letsmuggleoutonepgfmath@smuggleone
    makeatother
    begin{document}
    begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
    localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
    %smuggleoutone#1
    }]
    begin{scope}[local bounding box=extra]
    path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
    pgfextra{xdefmyangle{n1}};
    node at (1,0) {myangle};
    end{scope}
    node[anchor=south] at (extra.north) {using verb|pgfextra|};
    %
    begin{scope}[local bounding box=globalize,xshift=3cm]
    path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
    [globalize={n1}{myangle}];
    node at (1,0) {myangle};
    end{scope}
    node[anchor=south] at (globalize.north) {using texttt{globalize}};
    %
    xdefmyangle{7}
    begin{scope}[local bounding box=localize,xshift=6cm]
    path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
    [localize={n1}{myangle}];
    node at (1,0) {myangle};
    end{scope}
    node[anchor=south] at (localize.north) {attempt to smuggle};
    %
    end{tikzpicture}
    end{document}


    enter image description here



    The two options on the left do partly what I am seeking to do, namely broadcast the macro myangle outside the path. However, they do it at the expense of making myangle global. TikZ has some internal commands that may allow one to avoid this, and to just smuggle the macro outside the path. Specifically, @DavidCarlisle suggested in the chat to use pgfmath@smuggleone. However, my above attempts failed, i.e. if I uncomment



    %smuggleoutone#1


    the code produces errors.



    QUESTION: Can one smuggle the macro outside the group without making it global?



    "BONUS": Of course it would be great if there was an explanation what all the smuggle commands do.



    "BONUUUUS": Conceivably these methods may be useful independently of TikZ, so if there is a way not to make them depend on TikZ being loaded, this would be great, but is certainly not a requirement.










    share|improve this question



























      23












      23








      23


      3






      I am seeking to find something that allows me to "broadcast" macros outside a group. Concrete examples include paths and scopes in tizpictures. Here is an M(N)WE.



      documentclass[tikz,border=3.14mm]{standalone}
      usetikzlibrary{calc}
      makeatletter
      letsmuggleoutonepgfmath@smuggleone
      makeatother
      begin{document}
      begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
      localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
      %smuggleoutone#1
      }]
      begin{scope}[local bounding box=extra]
      path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
      pgfextra{xdefmyangle{n1}};
      node at (1,0) {myangle};
      end{scope}
      node[anchor=south] at (extra.north) {using verb|pgfextra|};
      %
      begin{scope}[local bounding box=globalize,xshift=3cm]
      path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
      [globalize={n1}{myangle}];
      node at (1,0) {myangle};
      end{scope}
      node[anchor=south] at (globalize.north) {using texttt{globalize}};
      %
      xdefmyangle{7}
      begin{scope}[local bounding box=localize,xshift=6cm]
      path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
      [localize={n1}{myangle}];
      node at (1,0) {myangle};
      end{scope}
      node[anchor=south] at (localize.north) {attempt to smuggle};
      %
      end{tikzpicture}
      end{document}


      enter image description here



      The two options on the left do partly what I am seeking to do, namely broadcast the macro myangle outside the path. However, they do it at the expense of making myangle global. TikZ has some internal commands that may allow one to avoid this, and to just smuggle the macro outside the path. Specifically, @DavidCarlisle suggested in the chat to use pgfmath@smuggleone. However, my above attempts failed, i.e. if I uncomment



      %smuggleoutone#1


      the code produces errors.



      QUESTION: Can one smuggle the macro outside the group without making it global?



      "BONUS": Of course it would be great if there was an explanation what all the smuggle commands do.



      "BONUUUUS": Conceivably these methods may be useful independently of TikZ, so if there is a way not to make them depend on TikZ being loaded, this would be great, but is certainly not a requirement.










      share|improve this question
















      I am seeking to find something that allows me to "broadcast" macros outside a group. Concrete examples include paths and scopes in tizpictures. Here is an M(N)WE.



      documentclass[tikz,border=3.14mm]{standalone}
      usetikzlibrary{calc}
      makeatletter
      letsmuggleoutonepgfmath@smuggleone
      makeatother
      begin{document}
      begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
      localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
      %smuggleoutone#1
      }]
      begin{scope}[local bounding box=extra]
      path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
      pgfextra{xdefmyangle{n1}};
      node at (1,0) {myangle};
      end{scope}
      node[anchor=south] at (extra.north) {using verb|pgfextra|};
      %
      begin{scope}[local bounding box=globalize,xshift=3cm]
      path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
      [globalize={n1}{myangle}];
      node at (1,0) {myangle};
      end{scope}
      node[anchor=south] at (globalize.north) {using texttt{globalize}};
      %
      xdefmyangle{7}
      begin{scope}[local bounding box=localize,xshift=6cm]
      path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
      [localize={n1}{myangle}];
      node at (1,0) {myangle};
      end{scope}
      node[anchor=south] at (localize.north) {attempt to smuggle};
      %
      end{tikzpicture}
      end{document}


      enter image description here



      The two options on the left do partly what I am seeking to do, namely broadcast the macro myangle outside the path. However, they do it at the expense of making myangle global. TikZ has some internal commands that may allow one to avoid this, and to just smuggle the macro outside the path. Specifically, @DavidCarlisle suggested in the chat to use pgfmath@smuggleone. However, my above attempts failed, i.e. if I uncomment



      %smuggleoutone#1


      the code produces errors.



      QUESTION: Can one smuggle the macro outside the group without making it global?



      "BONUS": Of course it would be great if there was an explanation what all the smuggle commands do.



      "BONUUUUS": Conceivably these methods may be useful independently of TikZ, so if there is a way not to make them depend on TikZ being loaded, this would be great, but is certainly not a requirement.







      tikz-pgf tex-core






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 20 at 1:35







      marmot

















      asked Jan 20 at 0:16









      marmotmarmot

      105k4126241




      105k4126241






















          3 Answers
          3






          active

          oldest

          votes


















          28














          You can "smuggle" definitions out of their group with the TeX primitive aftergroup. I'll first explain what aftergroup does, then give a possible definition of smuggleone using aftergroup and finally apply it to your MWE.



          The short answer is that you could define smuggleone (I've removed "out" from the name) as



          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }


          If you paste in this definition and replace smuggleoutone#1 by smuggleone#2 in your MWE it should work. (Note that you were passing the wrong argument to smuggleoutone, it should have been #2 instead of #1.)





          About aftergroup:



          It is possible to insert a single token right after the end of the current group using aftergroup<token>.
          You can only smuggle out one token at a time, so if you want to move out something consisting of multiple tokens (like a definition) you'll need to aftergroup each of these tokens separately. This includes things like braces ({}), so for instance



          {aftergroupdefaftergroupabcaftergroup{aftergroup Aaftergroup Baftergroup Caftergroup}}


          is equivalent to {}defabc{ABC}.



          This is quite a hassle, so the following may be more practical:



          {gdefsomethingunique{defabc{ABC}}aftergroupsomethingunique}


          This works by globally assigning defabc{ABC} to somethingunique and inserting that after the end of the group.
          If ABC is replaced by some macro, say ABC, that is only defined within the current group and that you want to be fully expanded then you'll want to use xdef instead:



          {%
          newcommand*ABC{ABC}%
          xdefsomethingunique{defnoexpandabc{ABC}}%
          aftergroupsomethingunique
          }


          I've inserted noexpand in front of abc because we don't want abc to be expanded.
          If you only want ABC to be expanded once you can instead use the slightly more complicated



          {
          newcommand*ABC{somethingthatshouldntbeexpanded}%
          xdefsomethingunique{defnoexpandabc{unexpandedexpandafter{ABC}}}%
          aftergroupsomethingunique
          }


          (The primitives noexpand, unexpanded and expandafter are all explained in this this answer.)



          To smuggle the definition of abc out of a group you can do what I just did above with ABC replaced by abc itself.
          That way abc will be defined as itself (expanded once) immediately after the end of the group.



          There's also AfterGroup from the etextools package.
          It acts mostly like aftergroup, but it takes an argument that can consist of any number of tokens.
          So, for instance, Aftergroup{defabc{ABC}} inserts defabc{ABC} after the current group without all of the aforementioned hassle.
          There's also a starred version, Aftergroup*, that does the same thing but first expands its arguments fully.




          Don't use the etextools package though! It is apparently buggy and no longer maintained and it is incompatible with a bunch of other packages. (Thanks to Ulrike Fischer for pointing that out, here are a few examples: 1, 2, 3, 4.)




          Even though you shouldn't use the package, AfterGroup itself can be quite useful. It is defined as follows:



          makeatletter %% <- make @ usable in command names
          newcountettl@fter
          newrobustcmdAfterGroup{@ifstar{ettl@AfterGroup@firstofone}{ettl@AfterGroupunexpanded}}
          newrobustcmdettl@AfterGroup[2]{%
          csxdef{ettl@fterGroupnumbernumexprtheettl@fter+1}%
          {globalcsundef{ettl@fterGroupnumbernumexprtheettl@fter+1}#1{#2}}%
          globaladvanceettl@fter@ne
          expandafteraftergroupcsname ettl@fterGrouptheettl@fterendcsname}
          makeatother %% <- revert @




          Defining smuggleone:



          To smuggle a macro that was already defined past the end of a group, it may be more effective to use let instead of def.
          One advantage is that it will also works for macros with arguments:



          {
          newcommand*abc[1]{``#1''}%
          globalletsomethinguniqueabc
          aftergroupletaftergroupabcaftergroupsomethingunique
          }
          abc{This works!}


          This leads us to a possible definition of smuggleone.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggleoneabc
          abc{Local definition}
          }par
          abc{Local definition}
          }par
          abc{Global definition}

          end{document}


          output



          The reason for the use of a counter here is that if you use somethingunique every time you're smuggling something, it won't really be unique.
          Whenever multiple smuggling operations are happening consescutively, because you're using smuggleone multiple times from within the same group or from a group contained in another one where smuggleone is used, this will cause trouble.
          The above command therefore creates smuggle@<n> the <n>-th time it is used.



          This can be made more efficient (memory-wise) by reusing these command sequences as much as possible, as in jfbu's answer.





          All of this applied to your MWE:



          Here is your MWE with two changes: (1) I've added the definition of smuggleone and (2) I've replaced %smuggleoutone#1 by smuggleone#2.



          documentclass[tikz,border=3.14mm]{standalone}
          usetikzlibrary{calc}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}
          begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
          localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
          smuggleone#2
          }]
          begin{scope}[local bounding box=extra]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          pgfextra{xdefmyangle{n1}};
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (extra.north) {using verb|pgfextra|};
          %
          begin{scope}[local bounding box=globalize,xshift=3cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [globalize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}


          output







          Addendum



          Here's a smuggle macro that works up to depth 10. It doesn't let you smuggle anything across eleven borders because 10 is two tokens (yeah, that's a stupid reason).
          I could make it work for any depth, but I like how short the definition currently is and it seems unlikely that any sane person would need this.



          The syntax is smuggle[<depth>]{<macro>}, and the default <depth> is 1.
          It works by calling smuggleone and then also aftergrouping smuggle[<depth-1>]{<macro>}.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }
          DeclareRobustCommandsmuggle[2][1]{%
          smuggleone{#2}%
          ifnum#1>1
          aftergroupsmuggleaftergroup[expandafteraftergroupthenumexpr#1-1aftergroup]aftergroup#2%
          fi
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}
          {%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggle[2]{abc}%
          Definition at depth 3: abc{Local definition}
          }par
          Definition of depth 2: abc{Local definition}
          }par
          Definition of depth 1: abc{Local definition}
          }par
          Definition at depth 0: abc{Global definition}

          end{document}


          output






          share|improve this answer





















          • 2





            Don't use etextools. Search the site for some of its incompabilies.

            – Ulrike Fischer
            Jan 20 at 7:36











          • @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

            – Circumscribe
            Jan 20 at 9:35











          • come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

            – user4686
            Jan 20 at 15:17











          • Hah, indeed! :)

            – Circumscribe
            Jan 20 at 15:19











          • @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

            – marmot
            Jan 20 at 23:53



















          9














          The usual approach is to expandafter around the end-of-group



          begingroup
          % Various things
          defresult{some-tokens-that-need-to-escape}%
          expandafterendgroup
          expandafterdefexpandafterresultexpandafter{result}


          That can be expressed slightly more concisely if using expl3



          group_begin:
          % Stuff to set
          tl_set:Nn l_result_tl { some-tokens-that-need-to-escape }
          exp_args:NNNV group_end:
          tl_set:Nn l_result_tl l_result_tl


          In either case, one could define something like



          protecteddefsmuggleone#1#2endgroup{%
          #2%
          expandafterendgroup
          expandafterdefexpandafter#1expandafter{#1}%
          }





          share|improve this answer



















          • 1





            I am wondering if you could add an example for how this is to be used in my above MWE?

            – marmot
            Jan 20 at 16:02



















          9














          This covers various things:




          • smuggling a (no-parameter; see bottom of answer for macros with parameters) macro one level up,


          • (bizarre, for fun) smuggle it two level up, but it remains undefined one level up,


          • (more useful) smuggle one level up the contents of some macro, which is way to execute after group closes arbitrarily many tokens (if they are still defined at that level of course).



          There is some subtlety in the way some globally defined auxiliary macros are indexed (their index is never globally increased), but I think it is ok. I hesitated about adding extra code to let them globally undefined once used, but did not do that finally. The same index will be used multiple times, but I think no non-yet needed thing ever gets overwritten. (although I may need to think about it more).



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%


          makeatother

          begin{document}

          tt

          begingroup
          typeout{DEPTH 1}%
          deffuzz{FUZZ defined at depth 1 and smuggled}%
          SmuggleMacrofuzz
          begingroup
          typeout{DEPTH 2}%
          defbaz{BAZ defined at depth 2 and smuggled up two}%
          SmuggleMacroUpTwobaz
          begingroup
          typeout{DEPTH 3}%
          DEPTH 3par
          deffoo{FOO defined at depth 3 and smuggled}%
          SmuggleMacrofoo
          defbar{BAR defined at depth 3 and smuggled up two}%
          SmuggleMacroUpTwobar
          END OF FIRST DEPTH 3par
          endgroup
          at depth 2 in-between the two depth 3par
          stringfoospace has meaning meaningfoospace and will be smuggled againpar
          stringbarspace has meaning meaningbarpar
          SmuggleMacrofoo
          begingroup
          DEPTH 3par
          typeout{SECOND TIMES AT DEPTH 3}%
          deffoofoo{FOOFOO defined at (second) depth 3 and smuggled}%
          SmuggleMacrofoofoo
          defTruc{par Hello, I am stringTrucspace
          I was defined at depth 3, but got executed
          at depth 2!par
          My own meaning is now: meaningTrucpar
          typeout{DEPTH 2 AFTER 3}}%
          showTruc
          SmuggleValueTruc
          END OF SECOND DEPTH 3par
          endgroup
          BACK TO DEPTH 2 (after executing aftergroup tokens)par
          showTruc
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 1 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          stringbarspace has meaning meaningbarpar
          typeout{DEPTH 1 AFTER 2}%
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 0 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          typeout{DEPTH 0 AFTER 1}
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar

          end{document}


          enter image description here



          DEPTH 1
          DEPTH 2
          DEPTH 3

          SECOND TIMES AT DEPTH 3
          > Truc=macro:
          ->par Hello, I am string Truc space I was defined at depth 3, but got executed at depth 2!par My own meaning is now: meaning Truc par typeout {DEPTH 2 AFTER 3}.
          l.77 showTruc


          DEPTH 2 AFTER 3
          > Truc=undefined.
          l.82 showTruc

          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.83 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.84 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.85 showfoo

          > foofoo=macro:
          ->FOOFOO defined at (second) depth 3 and smuggled.
          l.86 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.87 showbar

          DEPTH 1 AFTER 2
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.92 showfuzz

          > baz=undefined.
          l.93 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.94 showfoo

          > foofoo=undefined.
          l.95 showfoofoo

          > bar=macro:
          ->BAR defined at depth 3 and smuggled up two.
          l.96 showbar

          DEPTH 0 AFTER 1
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.101 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.102 showbaz

          > foo=undefined.
          l.103 showfoo

          > foofoo=undefined.
          l.104 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.105 showbar






          Addendum



          I am adding SmuggleMacroNtimesUp <number>.macro which will let the macro be known <number> levels up (of course, to the extent that its meaning uses tokens known at these levels...). Currently only parameter less macros, because this is how I started this...



          Not much tested. In fact only tested on the single example below...



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#3expandafter{#3}}%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          % This one makes **executes the macro**
          % at all levels 1, 2, ..., N up.
          % Syntax SmuggleValueNtimesUp<number>.macro
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          deffoo{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.foopar}%
          15.foopar}%+1
          14.foopar}%+2
          13.foopar}%+3
          12.foopar}%+4
          11.foopar}%
          10.foopar}%
          9.foopar}%
          8.foopar}%+8
          7.foopar}%
          6.foopar}%
          5.foopar}%
          4.foopar}%+12
          3.foopar}%+13
          2.foopar}%
          1.foopar}%
          0.foopar

          end{document}


          enter image description here








          Final version



          Under pressure of @Circumscribe example I have refactored to handle macros with parameters. Not much tested... Added @marmot query about moving meaning to top level (aka bottom level...)



          Thus the defined things are




          • SmuggleMacro foo : makes foo keep its meaning one level up,


          • SmuggleMacroUpTwo foo: makes foo recover its meaning two levels up (but not one level up...)


          • SmuggleMacroNtimesUp <number>.foo : makes foo keep its meaning for the <number> less nested levels. Must be used with <number> at least 1.


          • SmuggleValueNtimesUp <number>.foo : executes the meaning of foo for the <number> less nested levels, via aftergroup so as soon as a more nested level is left. foo itselfs (if not globally defined) is not smuggled.


          • SmuggleMacroToTopfoo : makes foo known at bottom level (sic), but not at any intermediate level (of course while moving from inner to outer, once we reach bottom level, next time we enter a group foo will be known).



          (if the code looks crazy, it is also because it tries to define the less auxiliary storage macros, by keeping this idea of never globally stepping the index of these storage things)



          documentclass{article}
          usepackage{geometry}
          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux#1#2{%
          globallet#1#2%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLet
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLet{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLet@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLet@aux#1#2#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#3%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#3%
          }%
          %longdef@gobblethree#1#2#3{}%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleMacroNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          % SmuggleMacroToTop
          defSmuggleMacroToTop{%
          ifnumcurrentgrouplevel=z@
          expandafter@gobble
          else
          expandafterSmuggleMacro@ToTop
          fi
          }%
          defSmuggleMacro@ToTop{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroToTop@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLetToTop{%
          ifnumcurrentgrouplevel=z@
          expandafterlet
          else
          expandafterSmuggleLet@ToTop
          fi
          }%
          defSmuggleLet@ToTop{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLetToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLetToTop@aux#1#2#3{%
          globallet#1#3%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          defBAR#1#2#3{Hello, I am BAR}%
          SmuggleMacroBAR
          SmuggleMacroToTopBAR
          defBAZ#1#2#3#4{Hello, I am BAZ}%
          SmuggleMacroUpTwoBAZ
          deffoo#1#2{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.FOO meaningfoopar
          16.BAZ meaningBAZpar
          16.BAR meaningBARpar
          defx{leavevmodellap{aaa }}%
          SmuggleValueNtimesUp7.x
          medskip}%
          15.FOO meaningfoopar
          15.BAZ meaningBAZpar
          15.BAR meaningBARparmedskip}%
          14.FOO meaningfoopar
          14.BAZ meaningBAZpar
          14.BAR meaningBARparmedskip}%
          13.FOO meaningfoopar}%+3
          12.FOO meaningfoopar}%+4
          11.FOO meaningfoopar}%
          10.FOO meaningfoopar}%
          9.FOO meaningfoopar
          9.BAR meaningBARpar
          }%
          8.FOO meaningfoopar}%+8
          7.FOO meaningfoopar}%
          6.FOO meaningfoopar}%
          5.FOO meaningfoopar
          5.BAR meaningBARpar}%
          4.FOO meaningfoopar}%+12
          3.FOO meaningfoopar}%+13
          2.FOO meaningfoopar}%
          1.FOO meaningfoopar}%
          0.FOO meaningfoopar
          0.BAR meaningBARpar
          end{document}


          enter image description here






          share|improve this answer


























          • although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

            – user4686
            Jan 20 at 13:33











          • Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

            – Circumscribe
            Jan 20 at 14:20













          • @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

            – user4686
            Jan 20 at 15:04













          • Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

            – marmot
            Jan 20 at 17:56











          • @marmot I understood that I would become rich, did I get that right?

            – user4686
            Jan 20 at 17:58











          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%2f470961%2fhow-to-properly-smuggle-with-or-even-without-tikz%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          28














          You can "smuggle" definitions out of their group with the TeX primitive aftergroup. I'll first explain what aftergroup does, then give a possible definition of smuggleone using aftergroup and finally apply it to your MWE.



          The short answer is that you could define smuggleone (I've removed "out" from the name) as



          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }


          If you paste in this definition and replace smuggleoutone#1 by smuggleone#2 in your MWE it should work. (Note that you were passing the wrong argument to smuggleoutone, it should have been #2 instead of #1.)





          About aftergroup:



          It is possible to insert a single token right after the end of the current group using aftergroup<token>.
          You can only smuggle out one token at a time, so if you want to move out something consisting of multiple tokens (like a definition) you'll need to aftergroup each of these tokens separately. This includes things like braces ({}), so for instance



          {aftergroupdefaftergroupabcaftergroup{aftergroup Aaftergroup Baftergroup Caftergroup}}


          is equivalent to {}defabc{ABC}.



          This is quite a hassle, so the following may be more practical:



          {gdefsomethingunique{defabc{ABC}}aftergroupsomethingunique}


          This works by globally assigning defabc{ABC} to somethingunique and inserting that after the end of the group.
          If ABC is replaced by some macro, say ABC, that is only defined within the current group and that you want to be fully expanded then you'll want to use xdef instead:



          {%
          newcommand*ABC{ABC}%
          xdefsomethingunique{defnoexpandabc{ABC}}%
          aftergroupsomethingunique
          }


          I've inserted noexpand in front of abc because we don't want abc to be expanded.
          If you only want ABC to be expanded once you can instead use the slightly more complicated



          {
          newcommand*ABC{somethingthatshouldntbeexpanded}%
          xdefsomethingunique{defnoexpandabc{unexpandedexpandafter{ABC}}}%
          aftergroupsomethingunique
          }


          (The primitives noexpand, unexpanded and expandafter are all explained in this this answer.)



          To smuggle the definition of abc out of a group you can do what I just did above with ABC replaced by abc itself.
          That way abc will be defined as itself (expanded once) immediately after the end of the group.



          There's also AfterGroup from the etextools package.
          It acts mostly like aftergroup, but it takes an argument that can consist of any number of tokens.
          So, for instance, Aftergroup{defabc{ABC}} inserts defabc{ABC} after the current group without all of the aforementioned hassle.
          There's also a starred version, Aftergroup*, that does the same thing but first expands its arguments fully.




          Don't use the etextools package though! It is apparently buggy and no longer maintained and it is incompatible with a bunch of other packages. (Thanks to Ulrike Fischer for pointing that out, here are a few examples: 1, 2, 3, 4.)




          Even though you shouldn't use the package, AfterGroup itself can be quite useful. It is defined as follows:



          makeatletter %% <- make @ usable in command names
          newcountettl@fter
          newrobustcmdAfterGroup{@ifstar{ettl@AfterGroup@firstofone}{ettl@AfterGroupunexpanded}}
          newrobustcmdettl@AfterGroup[2]{%
          csxdef{ettl@fterGroupnumbernumexprtheettl@fter+1}%
          {globalcsundef{ettl@fterGroupnumbernumexprtheettl@fter+1}#1{#2}}%
          globaladvanceettl@fter@ne
          expandafteraftergroupcsname ettl@fterGrouptheettl@fterendcsname}
          makeatother %% <- revert @




          Defining smuggleone:



          To smuggle a macro that was already defined past the end of a group, it may be more effective to use let instead of def.
          One advantage is that it will also works for macros with arguments:



          {
          newcommand*abc[1]{``#1''}%
          globalletsomethinguniqueabc
          aftergroupletaftergroupabcaftergroupsomethingunique
          }
          abc{This works!}


          This leads us to a possible definition of smuggleone.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggleoneabc
          abc{Local definition}
          }par
          abc{Local definition}
          }par
          abc{Global definition}

          end{document}


          output



          The reason for the use of a counter here is that if you use somethingunique every time you're smuggling something, it won't really be unique.
          Whenever multiple smuggling operations are happening consescutively, because you're using smuggleone multiple times from within the same group or from a group contained in another one where smuggleone is used, this will cause trouble.
          The above command therefore creates smuggle@<n> the <n>-th time it is used.



          This can be made more efficient (memory-wise) by reusing these command sequences as much as possible, as in jfbu's answer.





          All of this applied to your MWE:



          Here is your MWE with two changes: (1) I've added the definition of smuggleone and (2) I've replaced %smuggleoutone#1 by smuggleone#2.



          documentclass[tikz,border=3.14mm]{standalone}
          usetikzlibrary{calc}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}
          begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
          localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
          smuggleone#2
          }]
          begin{scope}[local bounding box=extra]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          pgfextra{xdefmyangle{n1}};
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (extra.north) {using verb|pgfextra|};
          %
          begin{scope}[local bounding box=globalize,xshift=3cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [globalize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}


          output







          Addendum



          Here's a smuggle macro that works up to depth 10. It doesn't let you smuggle anything across eleven borders because 10 is two tokens (yeah, that's a stupid reason).
          I could make it work for any depth, but I like how short the definition currently is and it seems unlikely that any sane person would need this.



          The syntax is smuggle[<depth>]{<macro>}, and the default <depth> is 1.
          It works by calling smuggleone and then also aftergrouping smuggle[<depth-1>]{<macro>}.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }
          DeclareRobustCommandsmuggle[2][1]{%
          smuggleone{#2}%
          ifnum#1>1
          aftergroupsmuggleaftergroup[expandafteraftergroupthenumexpr#1-1aftergroup]aftergroup#2%
          fi
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}
          {%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggle[2]{abc}%
          Definition at depth 3: abc{Local definition}
          }par
          Definition of depth 2: abc{Local definition}
          }par
          Definition of depth 1: abc{Local definition}
          }par
          Definition at depth 0: abc{Global definition}

          end{document}


          output






          share|improve this answer





















          • 2





            Don't use etextools. Search the site for some of its incompabilies.

            – Ulrike Fischer
            Jan 20 at 7:36











          • @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

            – Circumscribe
            Jan 20 at 9:35











          • come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

            – user4686
            Jan 20 at 15:17











          • Hah, indeed! :)

            – Circumscribe
            Jan 20 at 15:19











          • @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

            – marmot
            Jan 20 at 23:53
















          28














          You can "smuggle" definitions out of their group with the TeX primitive aftergroup. I'll first explain what aftergroup does, then give a possible definition of smuggleone using aftergroup and finally apply it to your MWE.



          The short answer is that you could define smuggleone (I've removed "out" from the name) as



          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }


          If you paste in this definition and replace smuggleoutone#1 by smuggleone#2 in your MWE it should work. (Note that you were passing the wrong argument to smuggleoutone, it should have been #2 instead of #1.)





          About aftergroup:



          It is possible to insert a single token right after the end of the current group using aftergroup<token>.
          You can only smuggle out one token at a time, so if you want to move out something consisting of multiple tokens (like a definition) you'll need to aftergroup each of these tokens separately. This includes things like braces ({}), so for instance



          {aftergroupdefaftergroupabcaftergroup{aftergroup Aaftergroup Baftergroup Caftergroup}}


          is equivalent to {}defabc{ABC}.



          This is quite a hassle, so the following may be more practical:



          {gdefsomethingunique{defabc{ABC}}aftergroupsomethingunique}


          This works by globally assigning defabc{ABC} to somethingunique and inserting that after the end of the group.
          If ABC is replaced by some macro, say ABC, that is only defined within the current group and that you want to be fully expanded then you'll want to use xdef instead:



          {%
          newcommand*ABC{ABC}%
          xdefsomethingunique{defnoexpandabc{ABC}}%
          aftergroupsomethingunique
          }


          I've inserted noexpand in front of abc because we don't want abc to be expanded.
          If you only want ABC to be expanded once you can instead use the slightly more complicated



          {
          newcommand*ABC{somethingthatshouldntbeexpanded}%
          xdefsomethingunique{defnoexpandabc{unexpandedexpandafter{ABC}}}%
          aftergroupsomethingunique
          }


          (The primitives noexpand, unexpanded and expandafter are all explained in this this answer.)



          To smuggle the definition of abc out of a group you can do what I just did above with ABC replaced by abc itself.
          That way abc will be defined as itself (expanded once) immediately after the end of the group.



          There's also AfterGroup from the etextools package.
          It acts mostly like aftergroup, but it takes an argument that can consist of any number of tokens.
          So, for instance, Aftergroup{defabc{ABC}} inserts defabc{ABC} after the current group without all of the aforementioned hassle.
          There's also a starred version, Aftergroup*, that does the same thing but first expands its arguments fully.




          Don't use the etextools package though! It is apparently buggy and no longer maintained and it is incompatible with a bunch of other packages. (Thanks to Ulrike Fischer for pointing that out, here are a few examples: 1, 2, 3, 4.)




          Even though you shouldn't use the package, AfterGroup itself can be quite useful. It is defined as follows:



          makeatletter %% <- make @ usable in command names
          newcountettl@fter
          newrobustcmdAfterGroup{@ifstar{ettl@AfterGroup@firstofone}{ettl@AfterGroupunexpanded}}
          newrobustcmdettl@AfterGroup[2]{%
          csxdef{ettl@fterGroupnumbernumexprtheettl@fter+1}%
          {globalcsundef{ettl@fterGroupnumbernumexprtheettl@fter+1}#1{#2}}%
          globaladvanceettl@fter@ne
          expandafteraftergroupcsname ettl@fterGrouptheettl@fterendcsname}
          makeatother %% <- revert @




          Defining smuggleone:



          To smuggle a macro that was already defined past the end of a group, it may be more effective to use let instead of def.
          One advantage is that it will also works for macros with arguments:



          {
          newcommand*abc[1]{``#1''}%
          globalletsomethinguniqueabc
          aftergroupletaftergroupabcaftergroupsomethingunique
          }
          abc{This works!}


          This leads us to a possible definition of smuggleone.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggleoneabc
          abc{Local definition}
          }par
          abc{Local definition}
          }par
          abc{Global definition}

          end{document}


          output



          The reason for the use of a counter here is that if you use somethingunique every time you're smuggling something, it won't really be unique.
          Whenever multiple smuggling operations are happening consescutively, because you're using smuggleone multiple times from within the same group or from a group contained in another one where smuggleone is used, this will cause trouble.
          The above command therefore creates smuggle@<n> the <n>-th time it is used.



          This can be made more efficient (memory-wise) by reusing these command sequences as much as possible, as in jfbu's answer.





          All of this applied to your MWE:



          Here is your MWE with two changes: (1) I've added the definition of smuggleone and (2) I've replaced %smuggleoutone#1 by smuggleone#2.



          documentclass[tikz,border=3.14mm]{standalone}
          usetikzlibrary{calc}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}
          begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
          localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
          smuggleone#2
          }]
          begin{scope}[local bounding box=extra]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          pgfextra{xdefmyangle{n1}};
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (extra.north) {using verb|pgfextra|};
          %
          begin{scope}[local bounding box=globalize,xshift=3cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [globalize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}


          output







          Addendum



          Here's a smuggle macro that works up to depth 10. It doesn't let you smuggle anything across eleven borders because 10 is two tokens (yeah, that's a stupid reason).
          I could make it work for any depth, but I like how short the definition currently is and it seems unlikely that any sane person would need this.



          The syntax is smuggle[<depth>]{<macro>}, and the default <depth> is 1.
          It works by calling smuggleone and then also aftergrouping smuggle[<depth-1>]{<macro>}.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }
          DeclareRobustCommandsmuggle[2][1]{%
          smuggleone{#2}%
          ifnum#1>1
          aftergroupsmuggleaftergroup[expandafteraftergroupthenumexpr#1-1aftergroup]aftergroup#2%
          fi
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}
          {%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggle[2]{abc}%
          Definition at depth 3: abc{Local definition}
          }par
          Definition of depth 2: abc{Local definition}
          }par
          Definition of depth 1: abc{Local definition}
          }par
          Definition at depth 0: abc{Global definition}

          end{document}


          output






          share|improve this answer





















          • 2





            Don't use etextools. Search the site for some of its incompabilies.

            – Ulrike Fischer
            Jan 20 at 7:36











          • @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

            – Circumscribe
            Jan 20 at 9:35











          • come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

            – user4686
            Jan 20 at 15:17











          • Hah, indeed! :)

            – Circumscribe
            Jan 20 at 15:19











          • @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

            – marmot
            Jan 20 at 23:53














          28












          28








          28







          You can "smuggle" definitions out of their group with the TeX primitive aftergroup. I'll first explain what aftergroup does, then give a possible definition of smuggleone using aftergroup and finally apply it to your MWE.



          The short answer is that you could define smuggleone (I've removed "out" from the name) as



          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }


          If you paste in this definition and replace smuggleoutone#1 by smuggleone#2 in your MWE it should work. (Note that you were passing the wrong argument to smuggleoutone, it should have been #2 instead of #1.)





          About aftergroup:



          It is possible to insert a single token right after the end of the current group using aftergroup<token>.
          You can only smuggle out one token at a time, so if you want to move out something consisting of multiple tokens (like a definition) you'll need to aftergroup each of these tokens separately. This includes things like braces ({}), so for instance



          {aftergroupdefaftergroupabcaftergroup{aftergroup Aaftergroup Baftergroup Caftergroup}}


          is equivalent to {}defabc{ABC}.



          This is quite a hassle, so the following may be more practical:



          {gdefsomethingunique{defabc{ABC}}aftergroupsomethingunique}


          This works by globally assigning defabc{ABC} to somethingunique and inserting that after the end of the group.
          If ABC is replaced by some macro, say ABC, that is only defined within the current group and that you want to be fully expanded then you'll want to use xdef instead:



          {%
          newcommand*ABC{ABC}%
          xdefsomethingunique{defnoexpandabc{ABC}}%
          aftergroupsomethingunique
          }


          I've inserted noexpand in front of abc because we don't want abc to be expanded.
          If you only want ABC to be expanded once you can instead use the slightly more complicated



          {
          newcommand*ABC{somethingthatshouldntbeexpanded}%
          xdefsomethingunique{defnoexpandabc{unexpandedexpandafter{ABC}}}%
          aftergroupsomethingunique
          }


          (The primitives noexpand, unexpanded and expandafter are all explained in this this answer.)



          To smuggle the definition of abc out of a group you can do what I just did above with ABC replaced by abc itself.
          That way abc will be defined as itself (expanded once) immediately after the end of the group.



          There's also AfterGroup from the etextools package.
          It acts mostly like aftergroup, but it takes an argument that can consist of any number of tokens.
          So, for instance, Aftergroup{defabc{ABC}} inserts defabc{ABC} after the current group without all of the aforementioned hassle.
          There's also a starred version, Aftergroup*, that does the same thing but first expands its arguments fully.




          Don't use the etextools package though! It is apparently buggy and no longer maintained and it is incompatible with a bunch of other packages. (Thanks to Ulrike Fischer for pointing that out, here are a few examples: 1, 2, 3, 4.)




          Even though you shouldn't use the package, AfterGroup itself can be quite useful. It is defined as follows:



          makeatletter %% <- make @ usable in command names
          newcountettl@fter
          newrobustcmdAfterGroup{@ifstar{ettl@AfterGroup@firstofone}{ettl@AfterGroupunexpanded}}
          newrobustcmdettl@AfterGroup[2]{%
          csxdef{ettl@fterGroupnumbernumexprtheettl@fter+1}%
          {globalcsundef{ettl@fterGroupnumbernumexprtheettl@fter+1}#1{#2}}%
          globaladvanceettl@fter@ne
          expandafteraftergroupcsname ettl@fterGrouptheettl@fterendcsname}
          makeatother %% <- revert @




          Defining smuggleone:



          To smuggle a macro that was already defined past the end of a group, it may be more effective to use let instead of def.
          One advantage is that it will also works for macros with arguments:



          {
          newcommand*abc[1]{``#1''}%
          globalletsomethinguniqueabc
          aftergroupletaftergroupabcaftergroupsomethingunique
          }
          abc{This works!}


          This leads us to a possible definition of smuggleone.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggleoneabc
          abc{Local definition}
          }par
          abc{Local definition}
          }par
          abc{Global definition}

          end{document}


          output



          The reason for the use of a counter here is that if you use somethingunique every time you're smuggling something, it won't really be unique.
          Whenever multiple smuggling operations are happening consescutively, because you're using smuggleone multiple times from within the same group or from a group contained in another one where smuggleone is used, this will cause trouble.
          The above command therefore creates smuggle@<n> the <n>-th time it is used.



          This can be made more efficient (memory-wise) by reusing these command sequences as much as possible, as in jfbu's answer.





          All of this applied to your MWE:



          Here is your MWE with two changes: (1) I've added the definition of smuggleone and (2) I've replaced %smuggleoutone#1 by smuggleone#2.



          documentclass[tikz,border=3.14mm]{standalone}
          usetikzlibrary{calc}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}
          begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
          localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
          smuggleone#2
          }]
          begin{scope}[local bounding box=extra]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          pgfextra{xdefmyangle{n1}};
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (extra.north) {using verb|pgfextra|};
          %
          begin{scope}[local bounding box=globalize,xshift=3cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [globalize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}


          output







          Addendum



          Here's a smuggle macro that works up to depth 10. It doesn't let you smuggle anything across eleven borders because 10 is two tokens (yeah, that's a stupid reason).
          I could make it work for any depth, but I like how short the definition currently is and it seems unlikely that any sane person would need this.



          The syntax is smuggle[<depth>]{<macro>}, and the default <depth> is 1.
          It works by calling smuggleone and then also aftergrouping smuggle[<depth-1>]{<macro>}.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }
          DeclareRobustCommandsmuggle[2][1]{%
          smuggleone{#2}%
          ifnum#1>1
          aftergroupsmuggleaftergroup[expandafteraftergroupthenumexpr#1-1aftergroup]aftergroup#2%
          fi
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}
          {%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggle[2]{abc}%
          Definition at depth 3: abc{Local definition}
          }par
          Definition of depth 2: abc{Local definition}
          }par
          Definition of depth 1: abc{Local definition}
          }par
          Definition at depth 0: abc{Global definition}

          end{document}


          output






          share|improve this answer















          You can "smuggle" definitions out of their group with the TeX primitive aftergroup. I'll first explain what aftergroup does, then give a possible definition of smuggleone using aftergroup and finally apply it to your MWE.



          The short answer is that you could define smuggleone (I've removed "out" from the name) as



          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }


          If you paste in this definition and replace smuggleoutone#1 by smuggleone#2 in your MWE it should work. (Note that you were passing the wrong argument to smuggleoutone, it should have been #2 instead of #1.)





          About aftergroup:



          It is possible to insert a single token right after the end of the current group using aftergroup<token>.
          You can only smuggle out one token at a time, so if you want to move out something consisting of multiple tokens (like a definition) you'll need to aftergroup each of these tokens separately. This includes things like braces ({}), so for instance



          {aftergroupdefaftergroupabcaftergroup{aftergroup Aaftergroup Baftergroup Caftergroup}}


          is equivalent to {}defabc{ABC}.



          This is quite a hassle, so the following may be more practical:



          {gdefsomethingunique{defabc{ABC}}aftergroupsomethingunique}


          This works by globally assigning defabc{ABC} to somethingunique and inserting that after the end of the group.
          If ABC is replaced by some macro, say ABC, that is only defined within the current group and that you want to be fully expanded then you'll want to use xdef instead:



          {%
          newcommand*ABC{ABC}%
          xdefsomethingunique{defnoexpandabc{ABC}}%
          aftergroupsomethingunique
          }


          I've inserted noexpand in front of abc because we don't want abc to be expanded.
          If you only want ABC to be expanded once you can instead use the slightly more complicated



          {
          newcommand*ABC{somethingthatshouldntbeexpanded}%
          xdefsomethingunique{defnoexpandabc{unexpandedexpandafter{ABC}}}%
          aftergroupsomethingunique
          }


          (The primitives noexpand, unexpanded and expandafter are all explained in this this answer.)



          To smuggle the definition of abc out of a group you can do what I just did above with ABC replaced by abc itself.
          That way abc will be defined as itself (expanded once) immediately after the end of the group.



          There's also AfterGroup from the etextools package.
          It acts mostly like aftergroup, but it takes an argument that can consist of any number of tokens.
          So, for instance, Aftergroup{defabc{ABC}} inserts defabc{ABC} after the current group without all of the aforementioned hassle.
          There's also a starred version, Aftergroup*, that does the same thing but first expands its arguments fully.




          Don't use the etextools package though! It is apparently buggy and no longer maintained and it is incompatible with a bunch of other packages. (Thanks to Ulrike Fischer for pointing that out, here are a few examples: 1, 2, 3, 4.)




          Even though you shouldn't use the package, AfterGroup itself can be quite useful. It is defined as follows:



          makeatletter %% <- make @ usable in command names
          newcountettl@fter
          newrobustcmdAfterGroup{@ifstar{ettl@AfterGroup@firstofone}{ettl@AfterGroupunexpanded}}
          newrobustcmdettl@AfterGroup[2]{%
          csxdef{ettl@fterGroupnumbernumexprtheettl@fter+1}%
          {globalcsundef{ettl@fterGroupnumbernumexprtheettl@fter+1}#1{#2}}%
          globaladvanceettl@fter@ne
          expandafteraftergroupcsname ettl@fterGrouptheettl@fterendcsname}
          makeatother %% <- revert @




          Defining smuggleone:



          To smuggle a macro that was already defined past the end of a group, it may be more effective to use let instead of def.
          One advantage is that it will also works for macros with arguments:



          {
          newcommand*abc[1]{``#1''}%
          globalletsomethinguniqueabc
          aftergroupletaftergroupabcaftergroupsomethingunique
          }
          abc{This works!}


          This leads us to a possible definition of smuggleone.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggleoneabc
          abc{Local definition}
          }par
          abc{Local definition}
          }par
          abc{Global definition}

          end{document}


          output



          The reason for the use of a counter here is that if you use somethingunique every time you're smuggling something, it won't really be unique.
          Whenever multiple smuggling operations are happening consescutively, because you're using smuggleone multiple times from within the same group or from a group contained in another one where smuggleone is used, this will cause trouble.
          The above command therefore creates smuggle@<n> the <n>-th time it is used.



          This can be made more efficient (memory-wise) by reusing these command sequences as much as possible, as in jfbu's answer.





          All of this applied to your MWE:



          Here is your MWE with two changes: (1) I've added the definition of smuggleone and (2) I've replaced %smuggleoutone#1 by smuggleone#2.



          documentclass[tikz,border=3.14mm]{standalone}
          usetikzlibrary{calc}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }

          begin{document}
          begin{tikzpicture}[globalize/.code n args={2}{xdef#2{#1}},
          localize/.code n args={2}{pgfmathsetmacro{#2}{#1}typeout{#2}
          smuggleone#2
          }]
          begin{scope}[local bounding box=extra]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          pgfextra{xdefmyangle{n1}};
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (extra.north) {using verb|pgfextra|};
          %
          begin{scope}[local bounding box=globalize,xshift=3cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [globalize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}
          node[anchor=south] at (globalize.north) {using texttt{globalize}};
          %
          xdefmyangle{7}
          begin{scope}[local bounding box=localize,xshift=6cm]
          path let p1=($(2,1)-(0,0)$),n1={atan2(y1,x1)} in
          [localize={n1}{myangle}];
          node at (1,0) {myangle};
          end{scope}
          node[anchor=south] at (localize.north) {attempt to smuggle};
          %
          end{tikzpicture}
          end{document}


          output







          Addendum



          Here's a smuggle macro that works up to depth 10. It doesn't let you smuggle anything across eleven borders because 10 is two tokens (yeah, that's a stupid reason).
          I could make it work for any depth, but I like how short the definition currently is and it seems unlikely that any sane person would need this.



          The syntax is smuggle[<depth>]{<macro>}, and the default <depth> is 1.
          It works by calling smuggleone and then also aftergrouping smuggle[<depth-1>]{<macro>}.



          documentclass{article}

          newcounter{smuggle}
          DeclareRobustCommandsmuggleone[1]{%
          stepcounter{smuggle}%
          expandafterglobalexpandafterletcsname smuggle@arabic{smuggle}endcsname#1%
          aftergroupletaftergroup#1expandafteraftergroupcsname smuggle@arabic{smuggle}endcsname
          }
          DeclareRobustCommandsmuggle[2][1]{%
          smuggleone{#2}%
          ifnum#1>1
          aftergroupsmuggleaftergroup[expandafteraftergroupthenumexpr#1-1aftergroup]aftergroup#2%
          fi
          }

          begin{document}

          newcommand*abc[1]{textbf{#1}}
          {%
          {%
          {%
          renewcommand*abc[1]{``#1''}%
          smuggle[2]{abc}%
          Definition at depth 3: abc{Local definition}
          }par
          Definition of depth 2: abc{Local definition}
          }par
          Definition of depth 1: abc{Local definition}
          }par
          Definition at depth 0: abc{Global definition}

          end{document}


          output







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 21 at 0:19

























          answered Jan 20 at 3:54









          CircumscribeCircumscribe

          7,11121141




          7,11121141








          • 2





            Don't use etextools. Search the site for some of its incompabilies.

            – Ulrike Fischer
            Jan 20 at 7:36











          • @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

            – Circumscribe
            Jan 20 at 9:35











          • come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

            – user4686
            Jan 20 at 15:17











          • Hah, indeed! :)

            – Circumscribe
            Jan 20 at 15:19











          • @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

            – marmot
            Jan 20 at 23:53














          • 2





            Don't use etextools. Search the site for some of its incompabilies.

            – Ulrike Fischer
            Jan 20 at 7:36











          • @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

            – Circumscribe
            Jan 20 at 9:35











          • come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

            – user4686
            Jan 20 at 15:17











          • Hah, indeed! :)

            – Circumscribe
            Jan 20 at 15:19











          • @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

            – marmot
            Jan 20 at 23:53








          2




          2





          Don't use etextools. Search the site for some of its incompabilies.

          – Ulrike Fischer
          Jan 20 at 7:36





          Don't use etextools. Search the site for some of its incompabilies.

          – Ulrike Fischer
          Jan 20 at 7:36













          @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

          – Circumscribe
          Jan 20 at 9:35





          @UlrikeFischer: Oh, that is good to know. Do you have a suggestion about what to use instead? (I'll just copy the definition of Aftergroup for now.)

          – Circumscribe
          Jan 20 at 9:35













          come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

          – user4686
          Jan 20 at 15:17





          come on, we all need SmuggleOutTo{comma separated list of upper levels}foo, e.g., SmuggleOutTo{+1, +4, +6, +13..infty}Foo will mean let Foo be known 1 level up, 4 levels up, 6 levels up and 13 levels up and all the way to infty, whereas SmuggleOutTo{infty}Foo will smuggle only to top level. What are you waiting for to do the real job ? :)

          – user4686
          Jan 20 at 15:17













          Hah, indeed! :)

          – Circumscribe
          Jan 20 at 15:19





          Hah, indeed! :)

          – Circumscribe
          Jan 20 at 15:19













          @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

          – marmot
          Jan 20 at 23:53





          @Circumscribe No worries. It will take a while till I smuggle the information into my brain. ;-)

          – marmot
          Jan 20 at 23:53











          9














          The usual approach is to expandafter around the end-of-group



          begingroup
          % Various things
          defresult{some-tokens-that-need-to-escape}%
          expandafterendgroup
          expandafterdefexpandafterresultexpandafter{result}


          That can be expressed slightly more concisely if using expl3



          group_begin:
          % Stuff to set
          tl_set:Nn l_result_tl { some-tokens-that-need-to-escape }
          exp_args:NNNV group_end:
          tl_set:Nn l_result_tl l_result_tl


          In either case, one could define something like



          protecteddefsmuggleone#1#2endgroup{%
          #2%
          expandafterendgroup
          expandafterdefexpandafter#1expandafter{#1}%
          }





          share|improve this answer



















          • 1





            I am wondering if you could add an example for how this is to be used in my above MWE?

            – marmot
            Jan 20 at 16:02
















          9














          The usual approach is to expandafter around the end-of-group



          begingroup
          % Various things
          defresult{some-tokens-that-need-to-escape}%
          expandafterendgroup
          expandafterdefexpandafterresultexpandafter{result}


          That can be expressed slightly more concisely if using expl3



          group_begin:
          % Stuff to set
          tl_set:Nn l_result_tl { some-tokens-that-need-to-escape }
          exp_args:NNNV group_end:
          tl_set:Nn l_result_tl l_result_tl


          In either case, one could define something like



          protecteddefsmuggleone#1#2endgroup{%
          #2%
          expandafterendgroup
          expandafterdefexpandafter#1expandafter{#1}%
          }





          share|improve this answer



















          • 1





            I am wondering if you could add an example for how this is to be used in my above MWE?

            – marmot
            Jan 20 at 16:02














          9












          9








          9







          The usual approach is to expandafter around the end-of-group



          begingroup
          % Various things
          defresult{some-tokens-that-need-to-escape}%
          expandafterendgroup
          expandafterdefexpandafterresultexpandafter{result}


          That can be expressed slightly more concisely if using expl3



          group_begin:
          % Stuff to set
          tl_set:Nn l_result_tl { some-tokens-that-need-to-escape }
          exp_args:NNNV group_end:
          tl_set:Nn l_result_tl l_result_tl


          In either case, one could define something like



          protecteddefsmuggleone#1#2endgroup{%
          #2%
          expandafterendgroup
          expandafterdefexpandafter#1expandafter{#1}%
          }





          share|improve this answer













          The usual approach is to expandafter around the end-of-group



          begingroup
          % Various things
          defresult{some-tokens-that-need-to-escape}%
          expandafterendgroup
          expandafterdefexpandafterresultexpandafter{result}


          That can be expressed slightly more concisely if using expl3



          group_begin:
          % Stuff to set
          tl_set:Nn l_result_tl { some-tokens-that-need-to-escape }
          exp_args:NNNV group_end:
          tl_set:Nn l_result_tl l_result_tl


          In either case, one could define something like



          protecteddefsmuggleone#1#2endgroup{%
          #2%
          expandafterendgroup
          expandafterdefexpandafter#1expandafter{#1}%
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 20 at 9:00









          Joseph WrightJoseph Wright

          204k23560889




          204k23560889








          • 1





            I am wondering if you could add an example for how this is to be used in my above MWE?

            – marmot
            Jan 20 at 16:02














          • 1





            I am wondering if you could add an example for how this is to be used in my above MWE?

            – marmot
            Jan 20 at 16:02








          1




          1





          I am wondering if you could add an example for how this is to be used in my above MWE?

          – marmot
          Jan 20 at 16:02





          I am wondering if you could add an example for how this is to be used in my above MWE?

          – marmot
          Jan 20 at 16:02











          9














          This covers various things:




          • smuggling a (no-parameter; see bottom of answer for macros with parameters) macro one level up,


          • (bizarre, for fun) smuggle it two level up, but it remains undefined one level up,


          • (more useful) smuggle one level up the contents of some macro, which is way to execute after group closes arbitrarily many tokens (if they are still defined at that level of course).



          There is some subtlety in the way some globally defined auxiliary macros are indexed (their index is never globally increased), but I think it is ok. I hesitated about adding extra code to let them globally undefined once used, but did not do that finally. The same index will be used multiple times, but I think no non-yet needed thing ever gets overwritten. (although I may need to think about it more).



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%


          makeatother

          begin{document}

          tt

          begingroup
          typeout{DEPTH 1}%
          deffuzz{FUZZ defined at depth 1 and smuggled}%
          SmuggleMacrofuzz
          begingroup
          typeout{DEPTH 2}%
          defbaz{BAZ defined at depth 2 and smuggled up two}%
          SmuggleMacroUpTwobaz
          begingroup
          typeout{DEPTH 3}%
          DEPTH 3par
          deffoo{FOO defined at depth 3 and smuggled}%
          SmuggleMacrofoo
          defbar{BAR defined at depth 3 and smuggled up two}%
          SmuggleMacroUpTwobar
          END OF FIRST DEPTH 3par
          endgroup
          at depth 2 in-between the two depth 3par
          stringfoospace has meaning meaningfoospace and will be smuggled againpar
          stringbarspace has meaning meaningbarpar
          SmuggleMacrofoo
          begingroup
          DEPTH 3par
          typeout{SECOND TIMES AT DEPTH 3}%
          deffoofoo{FOOFOO defined at (second) depth 3 and smuggled}%
          SmuggleMacrofoofoo
          defTruc{par Hello, I am stringTrucspace
          I was defined at depth 3, but got executed
          at depth 2!par
          My own meaning is now: meaningTrucpar
          typeout{DEPTH 2 AFTER 3}}%
          showTruc
          SmuggleValueTruc
          END OF SECOND DEPTH 3par
          endgroup
          BACK TO DEPTH 2 (after executing aftergroup tokens)par
          showTruc
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 1 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          stringbarspace has meaning meaningbarpar
          typeout{DEPTH 1 AFTER 2}%
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 0 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          typeout{DEPTH 0 AFTER 1}
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar

          end{document}


          enter image description here



          DEPTH 1
          DEPTH 2
          DEPTH 3

          SECOND TIMES AT DEPTH 3
          > Truc=macro:
          ->par Hello, I am string Truc space I was defined at depth 3, but got executed at depth 2!par My own meaning is now: meaning Truc par typeout {DEPTH 2 AFTER 3}.
          l.77 showTruc


          DEPTH 2 AFTER 3
          > Truc=undefined.
          l.82 showTruc

          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.83 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.84 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.85 showfoo

          > foofoo=macro:
          ->FOOFOO defined at (second) depth 3 and smuggled.
          l.86 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.87 showbar

          DEPTH 1 AFTER 2
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.92 showfuzz

          > baz=undefined.
          l.93 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.94 showfoo

          > foofoo=undefined.
          l.95 showfoofoo

          > bar=macro:
          ->BAR defined at depth 3 and smuggled up two.
          l.96 showbar

          DEPTH 0 AFTER 1
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.101 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.102 showbaz

          > foo=undefined.
          l.103 showfoo

          > foofoo=undefined.
          l.104 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.105 showbar






          Addendum



          I am adding SmuggleMacroNtimesUp <number>.macro which will let the macro be known <number> levels up (of course, to the extent that its meaning uses tokens known at these levels...). Currently only parameter less macros, because this is how I started this...



          Not much tested. In fact only tested on the single example below...



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#3expandafter{#3}}%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          % This one makes **executes the macro**
          % at all levels 1, 2, ..., N up.
          % Syntax SmuggleValueNtimesUp<number>.macro
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          deffoo{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.foopar}%
          15.foopar}%+1
          14.foopar}%+2
          13.foopar}%+3
          12.foopar}%+4
          11.foopar}%
          10.foopar}%
          9.foopar}%
          8.foopar}%+8
          7.foopar}%
          6.foopar}%
          5.foopar}%
          4.foopar}%+12
          3.foopar}%+13
          2.foopar}%
          1.foopar}%
          0.foopar

          end{document}


          enter image description here








          Final version



          Under pressure of @Circumscribe example I have refactored to handle macros with parameters. Not much tested... Added @marmot query about moving meaning to top level (aka bottom level...)



          Thus the defined things are




          • SmuggleMacro foo : makes foo keep its meaning one level up,


          • SmuggleMacroUpTwo foo: makes foo recover its meaning two levels up (but not one level up...)


          • SmuggleMacroNtimesUp <number>.foo : makes foo keep its meaning for the <number> less nested levels. Must be used with <number> at least 1.


          • SmuggleValueNtimesUp <number>.foo : executes the meaning of foo for the <number> less nested levels, via aftergroup so as soon as a more nested level is left. foo itselfs (if not globally defined) is not smuggled.


          • SmuggleMacroToTopfoo : makes foo known at bottom level (sic), but not at any intermediate level (of course while moving from inner to outer, once we reach bottom level, next time we enter a group foo will be known).



          (if the code looks crazy, it is also because it tries to define the less auxiliary storage macros, by keeping this idea of never globally stepping the index of these storage things)



          documentclass{article}
          usepackage{geometry}
          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux#1#2{%
          globallet#1#2%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLet
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLet{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLet@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLet@aux#1#2#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#3%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#3%
          }%
          %longdef@gobblethree#1#2#3{}%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleMacroNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          % SmuggleMacroToTop
          defSmuggleMacroToTop{%
          ifnumcurrentgrouplevel=z@
          expandafter@gobble
          else
          expandafterSmuggleMacro@ToTop
          fi
          }%
          defSmuggleMacro@ToTop{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroToTop@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLetToTop{%
          ifnumcurrentgrouplevel=z@
          expandafterlet
          else
          expandafterSmuggleLet@ToTop
          fi
          }%
          defSmuggleLet@ToTop{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLetToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLetToTop@aux#1#2#3{%
          globallet#1#3%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          defBAR#1#2#3{Hello, I am BAR}%
          SmuggleMacroBAR
          SmuggleMacroToTopBAR
          defBAZ#1#2#3#4{Hello, I am BAZ}%
          SmuggleMacroUpTwoBAZ
          deffoo#1#2{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.FOO meaningfoopar
          16.BAZ meaningBAZpar
          16.BAR meaningBARpar
          defx{leavevmodellap{aaa }}%
          SmuggleValueNtimesUp7.x
          medskip}%
          15.FOO meaningfoopar
          15.BAZ meaningBAZpar
          15.BAR meaningBARparmedskip}%
          14.FOO meaningfoopar
          14.BAZ meaningBAZpar
          14.BAR meaningBARparmedskip}%
          13.FOO meaningfoopar}%+3
          12.FOO meaningfoopar}%+4
          11.FOO meaningfoopar}%
          10.FOO meaningfoopar}%
          9.FOO meaningfoopar
          9.BAR meaningBARpar
          }%
          8.FOO meaningfoopar}%+8
          7.FOO meaningfoopar}%
          6.FOO meaningfoopar}%
          5.FOO meaningfoopar
          5.BAR meaningBARpar}%
          4.FOO meaningfoopar}%+12
          3.FOO meaningfoopar}%+13
          2.FOO meaningfoopar}%
          1.FOO meaningfoopar}%
          0.FOO meaningfoopar
          0.BAR meaningBARpar
          end{document}


          enter image description here






          share|improve this answer


























          • although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

            – user4686
            Jan 20 at 13:33











          • Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

            – Circumscribe
            Jan 20 at 14:20













          • @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

            – user4686
            Jan 20 at 15:04













          • Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

            – marmot
            Jan 20 at 17:56











          • @marmot I understood that I would become rich, did I get that right?

            – user4686
            Jan 20 at 17:58
















          9














          This covers various things:




          • smuggling a (no-parameter; see bottom of answer for macros with parameters) macro one level up,


          • (bizarre, for fun) smuggle it two level up, but it remains undefined one level up,


          • (more useful) smuggle one level up the contents of some macro, which is way to execute after group closes arbitrarily many tokens (if they are still defined at that level of course).



          There is some subtlety in the way some globally defined auxiliary macros are indexed (their index is never globally increased), but I think it is ok. I hesitated about adding extra code to let them globally undefined once used, but did not do that finally. The same index will be used multiple times, but I think no non-yet needed thing ever gets overwritten. (although I may need to think about it more).



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%


          makeatother

          begin{document}

          tt

          begingroup
          typeout{DEPTH 1}%
          deffuzz{FUZZ defined at depth 1 and smuggled}%
          SmuggleMacrofuzz
          begingroup
          typeout{DEPTH 2}%
          defbaz{BAZ defined at depth 2 and smuggled up two}%
          SmuggleMacroUpTwobaz
          begingroup
          typeout{DEPTH 3}%
          DEPTH 3par
          deffoo{FOO defined at depth 3 and smuggled}%
          SmuggleMacrofoo
          defbar{BAR defined at depth 3 and smuggled up two}%
          SmuggleMacroUpTwobar
          END OF FIRST DEPTH 3par
          endgroup
          at depth 2 in-between the two depth 3par
          stringfoospace has meaning meaningfoospace and will be smuggled againpar
          stringbarspace has meaning meaningbarpar
          SmuggleMacrofoo
          begingroup
          DEPTH 3par
          typeout{SECOND TIMES AT DEPTH 3}%
          deffoofoo{FOOFOO defined at (second) depth 3 and smuggled}%
          SmuggleMacrofoofoo
          defTruc{par Hello, I am stringTrucspace
          I was defined at depth 3, but got executed
          at depth 2!par
          My own meaning is now: meaningTrucpar
          typeout{DEPTH 2 AFTER 3}}%
          showTruc
          SmuggleValueTruc
          END OF SECOND DEPTH 3par
          endgroup
          BACK TO DEPTH 2 (after executing aftergroup tokens)par
          showTruc
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 1 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          stringbarspace has meaning meaningbarpar
          typeout{DEPTH 1 AFTER 2}%
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 0 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          typeout{DEPTH 0 AFTER 1}
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar

          end{document}


          enter image description here



          DEPTH 1
          DEPTH 2
          DEPTH 3

          SECOND TIMES AT DEPTH 3
          > Truc=macro:
          ->par Hello, I am string Truc space I was defined at depth 3, but got executed at depth 2!par My own meaning is now: meaning Truc par typeout {DEPTH 2 AFTER 3}.
          l.77 showTruc


          DEPTH 2 AFTER 3
          > Truc=undefined.
          l.82 showTruc

          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.83 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.84 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.85 showfoo

          > foofoo=macro:
          ->FOOFOO defined at (second) depth 3 and smuggled.
          l.86 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.87 showbar

          DEPTH 1 AFTER 2
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.92 showfuzz

          > baz=undefined.
          l.93 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.94 showfoo

          > foofoo=undefined.
          l.95 showfoofoo

          > bar=macro:
          ->BAR defined at depth 3 and smuggled up two.
          l.96 showbar

          DEPTH 0 AFTER 1
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.101 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.102 showbaz

          > foo=undefined.
          l.103 showfoo

          > foofoo=undefined.
          l.104 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.105 showbar






          Addendum



          I am adding SmuggleMacroNtimesUp <number>.macro which will let the macro be known <number> levels up (of course, to the extent that its meaning uses tokens known at these levels...). Currently only parameter less macros, because this is how I started this...



          Not much tested. In fact only tested on the single example below...



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#3expandafter{#3}}%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          % This one makes **executes the macro**
          % at all levels 1, 2, ..., N up.
          % Syntax SmuggleValueNtimesUp<number>.macro
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          deffoo{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.foopar}%
          15.foopar}%+1
          14.foopar}%+2
          13.foopar}%+3
          12.foopar}%+4
          11.foopar}%
          10.foopar}%
          9.foopar}%
          8.foopar}%+8
          7.foopar}%
          6.foopar}%
          5.foopar}%
          4.foopar}%+12
          3.foopar}%+13
          2.foopar}%
          1.foopar}%
          0.foopar

          end{document}


          enter image description here








          Final version



          Under pressure of @Circumscribe example I have refactored to handle macros with parameters. Not much tested... Added @marmot query about moving meaning to top level (aka bottom level...)



          Thus the defined things are




          • SmuggleMacro foo : makes foo keep its meaning one level up,


          • SmuggleMacroUpTwo foo: makes foo recover its meaning two levels up (but not one level up...)


          • SmuggleMacroNtimesUp <number>.foo : makes foo keep its meaning for the <number> less nested levels. Must be used with <number> at least 1.


          • SmuggleValueNtimesUp <number>.foo : executes the meaning of foo for the <number> less nested levels, via aftergroup so as soon as a more nested level is left. foo itselfs (if not globally defined) is not smuggled.


          • SmuggleMacroToTopfoo : makes foo known at bottom level (sic), but not at any intermediate level (of course while moving from inner to outer, once we reach bottom level, next time we enter a group foo will be known).



          (if the code looks crazy, it is also because it tries to define the less auxiliary storage macros, by keeping this idea of never globally stepping the index of these storage things)



          documentclass{article}
          usepackage{geometry}
          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux#1#2{%
          globallet#1#2%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLet
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLet{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLet@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLet@aux#1#2#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#3%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#3%
          }%
          %longdef@gobblethree#1#2#3{}%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleMacroNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          % SmuggleMacroToTop
          defSmuggleMacroToTop{%
          ifnumcurrentgrouplevel=z@
          expandafter@gobble
          else
          expandafterSmuggleMacro@ToTop
          fi
          }%
          defSmuggleMacro@ToTop{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroToTop@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLetToTop{%
          ifnumcurrentgrouplevel=z@
          expandafterlet
          else
          expandafterSmuggleLet@ToTop
          fi
          }%
          defSmuggleLet@ToTop{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLetToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLetToTop@aux#1#2#3{%
          globallet#1#3%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          defBAR#1#2#3{Hello, I am BAR}%
          SmuggleMacroBAR
          SmuggleMacroToTopBAR
          defBAZ#1#2#3#4{Hello, I am BAZ}%
          SmuggleMacroUpTwoBAZ
          deffoo#1#2{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.FOO meaningfoopar
          16.BAZ meaningBAZpar
          16.BAR meaningBARpar
          defx{leavevmodellap{aaa }}%
          SmuggleValueNtimesUp7.x
          medskip}%
          15.FOO meaningfoopar
          15.BAZ meaningBAZpar
          15.BAR meaningBARparmedskip}%
          14.FOO meaningfoopar
          14.BAZ meaningBAZpar
          14.BAR meaningBARparmedskip}%
          13.FOO meaningfoopar}%+3
          12.FOO meaningfoopar}%+4
          11.FOO meaningfoopar}%
          10.FOO meaningfoopar}%
          9.FOO meaningfoopar
          9.BAR meaningBARpar
          }%
          8.FOO meaningfoopar}%+8
          7.FOO meaningfoopar}%
          6.FOO meaningfoopar}%
          5.FOO meaningfoopar
          5.BAR meaningBARpar}%
          4.FOO meaningfoopar}%+12
          3.FOO meaningfoopar}%+13
          2.FOO meaningfoopar}%
          1.FOO meaningfoopar}%
          0.FOO meaningfoopar
          0.BAR meaningBARpar
          end{document}


          enter image description here






          share|improve this answer


























          • although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

            – user4686
            Jan 20 at 13:33











          • Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

            – Circumscribe
            Jan 20 at 14:20













          • @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

            – user4686
            Jan 20 at 15:04













          • Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

            – marmot
            Jan 20 at 17:56











          • @marmot I understood that I would become rich, did I get that right?

            – user4686
            Jan 20 at 17:58














          9












          9








          9







          This covers various things:




          • smuggling a (no-parameter; see bottom of answer for macros with parameters) macro one level up,


          • (bizarre, for fun) smuggle it two level up, but it remains undefined one level up,


          • (more useful) smuggle one level up the contents of some macro, which is way to execute after group closes arbitrarily many tokens (if they are still defined at that level of course).



          There is some subtlety in the way some globally defined auxiliary macros are indexed (their index is never globally increased), but I think it is ok. I hesitated about adding extra code to let them globally undefined once used, but did not do that finally. The same index will be used multiple times, but I think no non-yet needed thing ever gets overwritten. (although I may need to think about it more).



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%


          makeatother

          begin{document}

          tt

          begingroup
          typeout{DEPTH 1}%
          deffuzz{FUZZ defined at depth 1 and smuggled}%
          SmuggleMacrofuzz
          begingroup
          typeout{DEPTH 2}%
          defbaz{BAZ defined at depth 2 and smuggled up two}%
          SmuggleMacroUpTwobaz
          begingroup
          typeout{DEPTH 3}%
          DEPTH 3par
          deffoo{FOO defined at depth 3 and smuggled}%
          SmuggleMacrofoo
          defbar{BAR defined at depth 3 and smuggled up two}%
          SmuggleMacroUpTwobar
          END OF FIRST DEPTH 3par
          endgroup
          at depth 2 in-between the two depth 3par
          stringfoospace has meaning meaningfoospace and will be smuggled againpar
          stringbarspace has meaning meaningbarpar
          SmuggleMacrofoo
          begingroup
          DEPTH 3par
          typeout{SECOND TIMES AT DEPTH 3}%
          deffoofoo{FOOFOO defined at (second) depth 3 and smuggled}%
          SmuggleMacrofoofoo
          defTruc{par Hello, I am stringTrucspace
          I was defined at depth 3, but got executed
          at depth 2!par
          My own meaning is now: meaningTrucpar
          typeout{DEPTH 2 AFTER 3}}%
          showTruc
          SmuggleValueTruc
          END OF SECOND DEPTH 3par
          endgroup
          BACK TO DEPTH 2 (after executing aftergroup tokens)par
          showTruc
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 1 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          stringbarspace has meaning meaningbarpar
          typeout{DEPTH 1 AFTER 2}%
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 0 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          typeout{DEPTH 0 AFTER 1}
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar

          end{document}


          enter image description here



          DEPTH 1
          DEPTH 2
          DEPTH 3

          SECOND TIMES AT DEPTH 3
          > Truc=macro:
          ->par Hello, I am string Truc space I was defined at depth 3, but got executed at depth 2!par My own meaning is now: meaning Truc par typeout {DEPTH 2 AFTER 3}.
          l.77 showTruc


          DEPTH 2 AFTER 3
          > Truc=undefined.
          l.82 showTruc

          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.83 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.84 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.85 showfoo

          > foofoo=macro:
          ->FOOFOO defined at (second) depth 3 and smuggled.
          l.86 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.87 showbar

          DEPTH 1 AFTER 2
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.92 showfuzz

          > baz=undefined.
          l.93 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.94 showfoo

          > foofoo=undefined.
          l.95 showfoofoo

          > bar=macro:
          ->BAR defined at depth 3 and smuggled up two.
          l.96 showbar

          DEPTH 0 AFTER 1
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.101 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.102 showbaz

          > foo=undefined.
          l.103 showfoo

          > foofoo=undefined.
          l.104 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.105 showbar






          Addendum



          I am adding SmuggleMacroNtimesUp <number>.macro which will let the macro be known <number> levels up (of course, to the extent that its meaning uses tokens known at these levels...). Currently only parameter less macros, because this is how I started this...



          Not much tested. In fact only tested on the single example below...



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#3expandafter{#3}}%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          % This one makes **executes the macro**
          % at all levels 1, 2, ..., N up.
          % Syntax SmuggleValueNtimesUp<number>.macro
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          deffoo{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.foopar}%
          15.foopar}%+1
          14.foopar}%+2
          13.foopar}%+3
          12.foopar}%+4
          11.foopar}%
          10.foopar}%
          9.foopar}%
          8.foopar}%+8
          7.foopar}%
          6.foopar}%
          5.foopar}%
          4.foopar}%+12
          3.foopar}%+13
          2.foopar}%
          1.foopar}%
          0.foopar

          end{document}


          enter image description here








          Final version



          Under pressure of @Circumscribe example I have refactored to handle macros with parameters. Not much tested... Added @marmot query about moving meaning to top level (aka bottom level...)



          Thus the defined things are




          • SmuggleMacro foo : makes foo keep its meaning one level up,


          • SmuggleMacroUpTwo foo: makes foo recover its meaning two levels up (but not one level up...)


          • SmuggleMacroNtimesUp <number>.foo : makes foo keep its meaning for the <number> less nested levels. Must be used with <number> at least 1.


          • SmuggleValueNtimesUp <number>.foo : executes the meaning of foo for the <number> less nested levels, via aftergroup so as soon as a more nested level is left. foo itselfs (if not globally defined) is not smuggled.


          • SmuggleMacroToTopfoo : makes foo known at bottom level (sic), but not at any intermediate level (of course while moving from inner to outer, once we reach bottom level, next time we enter a group foo will be known).



          (if the code looks crazy, it is also because it tries to define the less auxiliary storage macros, by keeping this idea of never globally stepping the index of these storage things)



          documentclass{article}
          usepackage{geometry}
          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux#1#2{%
          globallet#1#2%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLet
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLet{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLet@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLet@aux#1#2#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#3%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#3%
          }%
          %longdef@gobblethree#1#2#3{}%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleMacroNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          % SmuggleMacroToTop
          defSmuggleMacroToTop{%
          ifnumcurrentgrouplevel=z@
          expandafter@gobble
          else
          expandafterSmuggleMacro@ToTop
          fi
          }%
          defSmuggleMacro@ToTop{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroToTop@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLetToTop{%
          ifnumcurrentgrouplevel=z@
          expandafterlet
          else
          expandafterSmuggleLet@ToTop
          fi
          }%
          defSmuggleLet@ToTop{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLetToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLetToTop@aux#1#2#3{%
          globallet#1#3%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          defBAR#1#2#3{Hello, I am BAR}%
          SmuggleMacroBAR
          SmuggleMacroToTopBAR
          defBAZ#1#2#3#4{Hello, I am BAZ}%
          SmuggleMacroUpTwoBAZ
          deffoo#1#2{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.FOO meaningfoopar
          16.BAZ meaningBAZpar
          16.BAR meaningBARpar
          defx{leavevmodellap{aaa }}%
          SmuggleValueNtimesUp7.x
          medskip}%
          15.FOO meaningfoopar
          15.BAZ meaningBAZpar
          15.BAR meaningBARparmedskip}%
          14.FOO meaningfoopar
          14.BAZ meaningBAZpar
          14.BAR meaningBARparmedskip}%
          13.FOO meaningfoopar}%+3
          12.FOO meaningfoopar}%+4
          11.FOO meaningfoopar}%
          10.FOO meaningfoopar}%
          9.FOO meaningfoopar
          9.BAR meaningBARpar
          }%
          8.FOO meaningfoopar}%+8
          7.FOO meaningfoopar}%
          6.FOO meaningfoopar}%
          5.FOO meaningfoopar
          5.BAR meaningBARpar}%
          4.FOO meaningfoopar}%+12
          3.FOO meaningfoopar}%+13
          2.FOO meaningfoopar}%
          1.FOO meaningfoopar}%
          0.FOO meaningfoopar
          0.BAR meaningBARpar
          end{document}


          enter image description here






          share|improve this answer















          This covers various things:




          • smuggling a (no-parameter; see bottom of answer for macros with parameters) macro one level up,


          • (bizarre, for fun) smuggle it two level up, but it remains undefined one level up,


          • (more useful) smuggle one level up the contents of some macro, which is way to execute after group closes arbitrarily many tokens (if they are still defined at that level of course).



          There is some subtlety in the way some globally defined auxiliary macros are indexed (their index is never globally increased), but I think it is ok. I hesitated about adding extra code to let them globally undefined once used, but did not do that finally. The same index will be used multiple times, but I think no non-yet needed thing ever gets overwritten. (although I may need to think about it more).



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%


          makeatother

          begin{document}

          tt

          begingroup
          typeout{DEPTH 1}%
          deffuzz{FUZZ defined at depth 1 and smuggled}%
          SmuggleMacrofuzz
          begingroup
          typeout{DEPTH 2}%
          defbaz{BAZ defined at depth 2 and smuggled up two}%
          SmuggleMacroUpTwobaz
          begingroup
          typeout{DEPTH 3}%
          DEPTH 3par
          deffoo{FOO defined at depth 3 and smuggled}%
          SmuggleMacrofoo
          defbar{BAR defined at depth 3 and smuggled up two}%
          SmuggleMacroUpTwobar
          END OF FIRST DEPTH 3par
          endgroup
          at depth 2 in-between the two depth 3par
          stringfoospace has meaning meaningfoospace and will be smuggled againpar
          stringbarspace has meaning meaningbarpar
          SmuggleMacrofoo
          begingroup
          DEPTH 3par
          typeout{SECOND TIMES AT DEPTH 3}%
          deffoofoo{FOOFOO defined at (second) depth 3 and smuggled}%
          SmuggleMacrofoofoo
          defTruc{par Hello, I am stringTrucspace
          I was defined at depth 3, but got executed
          at depth 2!par
          My own meaning is now: meaningTrucpar
          typeout{DEPTH 2 AFTER 3}}%
          showTruc
          SmuggleValueTruc
          END OF SECOND DEPTH 3par
          endgroup
          BACK TO DEPTH 2 (after executing aftergroup tokens)par
          showTruc
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 1 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          stringbarspace has meaning meaningbarpar
          typeout{DEPTH 1 AFTER 2}%
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar
          endgroup
          BACK TO DEPTH 0 (after executing aftergroup tokens)par
          stringfoospace has meaning meaningfoopar
          typeout{DEPTH 0 AFTER 1}
          showfuzz
          showbaz
          showfoo
          showfoofoo
          showbar

          end{document}


          enter image description here



          DEPTH 1
          DEPTH 2
          DEPTH 3

          SECOND TIMES AT DEPTH 3
          > Truc=macro:
          ->par Hello, I am string Truc space I was defined at depth 3, but got executed at depth 2!par My own meaning is now: meaning Truc par typeout {DEPTH 2 AFTER 3}.
          l.77 showTruc


          DEPTH 2 AFTER 3
          > Truc=undefined.
          l.82 showTruc

          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.83 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.84 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.85 showfoo

          > foofoo=macro:
          ->FOOFOO defined at (second) depth 3 and smuggled.
          l.86 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.87 showbar

          DEPTH 1 AFTER 2
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.92 showfuzz

          > baz=undefined.
          l.93 showbaz

          > foo=macro:
          ->FOO defined at depth 3 and smuggled.
          l.94 showfoo

          > foofoo=undefined.
          l.95 showfoofoo

          > bar=macro:
          ->BAR defined at depth 3 and smuggled up two.
          l.96 showbar

          DEPTH 0 AFTER 1
          > fuzz=macro:
          ->FUZZ defined at depth 1 and smuggled.
          l.101 showfuzz

          > baz=macro:
          ->BAZ defined at depth 2 and smuggled up two.
          l.102 showbaz

          > foo=undefined.
          l.103 showfoo

          > foofoo=undefined.
          l.104 showfoofoo

          > bar=macro:
          ->mathaccent "7016relax .
          l.105 showbar






          Addendum



          I am adding SmuggleMacroNtimesUp <number>.macro which will let the macro be known <number> levels up (of course, to the extent that its meaning uses tokens known at these levels...). Currently only parameter less macros, because this is how I started this...



          Not much tested. In fact only tested on the single example below...



          documentclass{article}

          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux #1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#2expandafter{#2}}%
          aftergroupSmuggleValue
          aftergroup#1%
          }%
          defSmuggleValue{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleValue@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValue@aux #1#2{%
          globallet#1#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          expandaftergdefexpandafter#1expandafter
          {expandafterdefexpandafter#3expandafter{#3}}%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          % This one makes **executes the macro**
          % at all levels 1, 2, ..., N up.
          % Syntax SmuggleValueNtimesUp<number>.macro
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          deffoo{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.foopar}%
          15.foopar}%+1
          14.foopar}%+2
          13.foopar}%+3
          12.foopar}%+4
          11.foopar}%
          10.foopar}%
          9.foopar}%
          8.foopar}%+8
          7.foopar}%
          6.foopar}%
          5.foopar}%
          4.foopar}%+12
          3.foopar}%+13
          2.foopar}%
          1.foopar}%
          0.foopar

          end{document}


          enter image description here








          Final version



          Under pressure of @Circumscribe example I have refactored to handle macros with parameters. Not much tested... Added @marmot query about moving meaning to top level (aka bottom level...)



          Thus the defined things are




          • SmuggleMacro foo : makes foo keep its meaning one level up,


          • SmuggleMacroUpTwo foo: makes foo recover its meaning two levels up (but not one level up...)


          • SmuggleMacroNtimesUp <number>.foo : makes foo keep its meaning for the <number> less nested levels. Must be used with <number> at least 1.


          • SmuggleValueNtimesUp <number>.foo : executes the meaning of foo for the <number> less nested levels, via aftergroup so as soon as a more nested level is left. foo itselfs (if not globally defined) is not smuggled.


          • SmuggleMacroToTopfoo : makes foo known at bottom level (sic), but not at any intermediate level (of course while moving from inner to outer, once we reach bottom level, next time we enter a group foo will be known).



          (if the code looks crazy, it is also because it tries to define the less auxiliary storage macros, by keeping this idea of never globally stepping the index of these storage things)



          documentclass{article}
          usepackage{geometry}
          newcountgoodiescount

          makeatletter
          defSmuggleMacro{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacro@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacro@aux#1#2{%
          globallet#1#2%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          % This one will let the macro be known two levels higher,
          % but not if only one level higher
          defSmuggleMacroUpTwo{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleMacroUpTwo@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroUpTwo@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLet
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLet{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLet@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLet@aux#1#2#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#2%
          aftergroup#1%
          }%
          %
          % This one makes known the macros 1, 2, ..., N levels up.
          % Syntax SmuggleMacroNtimesUp<number>.macro
          defSmuggleMacroNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergrouplet
          aftergroup#3%
          aftergroup#1%
          expandafterSmuggleMacroNtimesUp@athenumexpr#2-1.#3%
          }%
          %longdef@gobblethree#1#2#3{}%
          defSmuggleMacroNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleMacroNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleNtimesUp@loop#1{%
          aftergroup#1%
          if.#1expandafteraftergroup
          else
          expandafterSmuggleNtimesUp@loop
          fi
          }%
          defSmuggleValueNtimesUp{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleValueNtimesUp@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleValueNtimesUp@aux#1#2.#3{%
          globallet#1#3%
          aftergroup#1%
          expandafterSmuggleValueNtimesUp@athenumexpr#2-1.#1%
          }%
          defSmuggleValueNtimesUp@a#1{%
          if0#1expandafter@gobbletwo
          else
          aftergroupSmuggleValueNtimesUp
          aftergroup #1%
          expandafterSmuggleNtimesUp@loop
          fi
          }%

          % SmuggleMacroToTop
          defSmuggleMacroToTop{%
          ifnumcurrentgrouplevel=z@
          expandafter@gobble
          else
          expandafterSmuggleMacro@ToTop
          fi
          }%
          defSmuggleMacro@ToTop{%
          advancegoodiescount 1 % not done globally!
          expandafterSmuggleMacroToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleMacroToTop@aux#1#2{%
          globallet#1#2%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          defSmuggleLetToTop{%
          ifnumcurrentgrouplevel=z@
          expandafterlet
          else
          expandafterSmuggleLet@ToTop
          fi
          }%
          defSmuggleLet@ToTop{%
          advancegoodiescount 1 % not done globally !
          expandafterSmuggleLetToTop@aux
          csname Goodiesthegoodiescountendcsname
          }%
          defSmuggleLetToTop@aux#1#2#3{%
          globallet#1#3%
          aftergroupSmuggleLetToTop
          aftergroup#2%
          aftergroup#1%
          }%
          makeatother

          begin{document}

          ttfamily

          deffoo{}
          {{{{{{{{% 8 deep
          {{{{{{{{% 16 deep
          defBAR#1#2#3{Hello, I am BAR}%
          SmuggleMacroBAR
          SmuggleMacroToTopBAR
          defBAZ#1#2#3#4{Hello, I am BAZ}%
          SmuggleMacroUpTwoBAZ
          deffoo#1#2{FOO defined at 16 will be made known all the way to 3}%
          SmuggleMacroNtimesUp13.foo
          16.FOO meaningfoopar
          16.BAZ meaningBAZpar
          16.BAR meaningBARpar
          defx{leavevmodellap{aaa }}%
          SmuggleValueNtimesUp7.x
          medskip}%
          15.FOO meaningfoopar
          15.BAZ meaningBAZpar
          15.BAR meaningBARparmedskip}%
          14.FOO meaningfoopar
          14.BAZ meaningBAZpar
          14.BAR meaningBARparmedskip}%
          13.FOO meaningfoopar}%+3
          12.FOO meaningfoopar}%+4
          11.FOO meaningfoopar}%
          10.FOO meaningfoopar}%
          9.FOO meaningfoopar
          9.BAR meaningBARpar
          }%
          8.FOO meaningfoopar}%+8
          7.FOO meaningfoopar}%
          6.FOO meaningfoopar}%
          5.FOO meaningfoopar
          5.BAR meaningBARpar}%
          4.FOO meaningfoopar}%+12
          3.FOO meaningfoopar}%+13
          2.FOO meaningfoopar}%
          1.FOO meaningfoopar}%
          0.FOO meaningfoopar
          0.BAR meaningBARpar
          end{document}


          enter image description here







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 20 at 17:54

























          answered Jan 20 at 11:33







          user4686




















          • although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

            – user4686
            Jan 20 at 13:33











          • Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

            – Circumscribe
            Jan 20 at 14:20













          • @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

            – user4686
            Jan 20 at 15:04













          • Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

            – marmot
            Jan 20 at 17:56











          • @marmot I understood that I would become rich, did I get that right?

            – user4686
            Jan 20 at 17:58



















          • although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

            – user4686
            Jan 20 at 13:33











          • Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

            – Circumscribe
            Jan 20 at 14:20













          • @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

            – user4686
            Jan 20 at 15:04













          • Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

            – marmot
            Jan 20 at 17:56











          • @marmot I understood that I would become rich, did I get that right?

            – user4686
            Jan 20 at 17:58

















          although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

          – user4686
          Jan 20 at 13:33





          although I may need to think about it more: I think it is fine, although I have not really thought at depth. (ah ah).

          – user4686
          Jan 20 at 13:33













          Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

          – Circumscribe
          Jan 20 at 14:20







          Trying to mentally parse SmuggleMacroUpTwo makes my head hurt, but it appears to be airtight. You're really minimising the number of different macros that need to be assigned by keeping track of how many smuggling operations are currently ongoing and assigning them appropriate numbers :).

          – Circumscribe
          Jan 20 at 14:20















          @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

          – user4686
          Jan 20 at 15:04







          @Circumscribe yes, after a group closes, new definition of a given index can only happen after or at same time its old meaning is actually needed, and when you open an inner group you can only then define macros with a higher index than what you had stored earlier as to be used after the outer group. Thus, ..., it should be airtight indeed, but indeed a bit head-spinning :)

          – user4686
          Jan 20 at 15:04















          Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

          – marmot
          Jan 20 at 17:56





          Did you read " Of course, infty means that this macro has the value in all LaTeX documents of the world. ;-) " ? ;-)

          – marmot
          Jan 20 at 17:56













          @marmot I understood that I would become rich, did I get that right?

          – user4686
          Jan 20 at 17:58





          @marmot I understood that I would become rich, did I get that right?

          – user4686
          Jan 20 at 17:58


















          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%2f470961%2fhow-to-properly-smuggle-with-or-even-without-tikz%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

          Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

          Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

          A Topological Invariant for $pi_3(U(n))$