1

In the bodeplot package, I defined new environments using (defined like this to avoid issues with externalization of tikz graphics)

\documentclass{standalone}
\usepackage{pgfplots,xparse}
\pgfplotsset{compat=1.18}
\NewDocumentEnvironment{MyEnv}{O{}mm+b}{
  \begin{tikzpicture}
    \begin{semilogxaxis}[xmin={#2},xmax={#3},ymin=0,ymax=1]
      #4
    \end{semilogxaxis}
  \end{tikzpicture}
}{}

I want users to be able to use the new environment to do things like this

\begin{document}
  \begin{MyEnv}[]{1e-1}{1e4}
    \draw[thick,blue,dashed] (axis cs:1,0) -- (axis cs:100,1);
    \addplot[variable=t,domain=1e-1:1e4] gnuplot {(t>100)?0.2:0.5};
  \end{MyEnv}
\end{document}

All of this works out for English language documents. However, if a user uses babel with any language that makes some characters in #4 active, the document cannot be compiled. For example, if I add

\usepackage[french]{babel}
\usetikzlibrary{babel}

to the preamble, I get compilation errors.

I managed to make it work for the French language work by checking for frenchbsetup and using

\AddToHook{env/MyEnv/begin}{\shorthandoff{;:!?}}

if it is detected. However, doing something like this for every active character in every language seems like the wrong approach to solve this issue.

Is there a better way detect and manage active characters in macros like this that will work with all languages supported by babel?

Rushi
  • 837
  • The b is functionally similar to the workaround suggested here to enable externalization. If there is a way to make the \NewDocumentEnvironment{MyEnv}{...}{\begin{tikzpicture}...} {...\end{tikzpicture}} syntax play nice with externalization, I am all for it! – Rushi Feb 03 '24 at 00:27
  • ok............. – David Carlisle Feb 03 '24 at 00:27
  • you can try \csname @safe@activestrue\endcsname. Or ask the babel maintainer to make the shorthands protected. – Ulrike Fischer Feb 03 '24 at 17:19
  • I tried adding \csname @safe@activestrue\endcsname to the preamble, but the error remains the same. I will try to reach out to the `babel' maintainer. – Rushi Feb 05 '24 at 01:38
  • your example compiles fine for me with \csname @safe@activestrue\endcsname in a current texlive. (But you should set that only locally in your environment). – Ulrike Fischer Feb 05 '24 at 19:56
  • I am using a fully updated MikTeX distribution. For me, it works if I use lualatex or xelatex, but not if I use pdflatex or latex. Weirdly, this is true with or without @safe@activestrue. The error disappears altogether if I use lualatex or xelatex. – Rushi Feb 06 '24 at 04:54
  • Ok, I isolated the issue. If I load the babel library using \usetikzlibrary{babel}, then I get compilation errors with or without \csname @safe@activestrue\endcsname. If the library is not loaded, then the compilation errors go away when \csname @safe@activestrue\endcsname is set. – Rushi Feb 06 '24 at 16:48

1 Answers1

4

I’m not sure how tikz deals with catcodes, but I presume they must be changed somehow to their default values, usually 12 (‘other’). And the only way is with \shorthandoff (or with the low level \catcode).

However, perhaps the following idea works for you: there is a macro named \dospecials storing ‘special’ characters, and babel adds shorthands to it. Since they are stored as macros (ie, ; is stored as \;), we need some trick to get the actual character. Then we can use \ifbabelshorthand:

\documentclass{article}

\usepackage[french]{babel}

\makeatletter \let\shorthandlist@empty \def\do#1{% \begingroup \lccode\~=#1\relax \lowercase{\ifbabelshorthand~{\g@addto@macro\shorthandlist{~}}{}} \endgroup} \dospecials \makeatother

\show\shorthandlist

This will show ->~:;!?., which, if we remove the characters added by \show, is ~:;!?. It may not work for you, but at least I tried .

EDIT: Once the shorthand list is assembled, it can be used to turn shorthands off in MyEnv using \AddToHook{env/MyEnv/begin}{\expandafter\shorthandoff\expandafter{\shorthandlist}}. Complete MWE:

\documentclass{standalone}
\usepackage{pgfplots,xparse}
\pgfplotsset{compat=1.18}
\usepackage[french]{babel}
\usetikzlibrary{babel}
\NewDocumentEnvironment{MyEnv}{O{}mm+b}{
    \begin{tikzpicture}
        \begin{semilogxaxis}[xmin={#2},xmax={#3},ymin=0,ymax=1]
            #4
        \end{semilogxaxis}
    \end{tikzpicture}
}{}

\makeatletter \let\shorthandlist@empty \def\do#1{% \begingroup \lccode\~=#1\relax \lowercase{\ifbabelshorthand~{\g@addto@macro\shorthandlist{~}}{}} \endgroup} \dospecials \makeatother \AddToHook{env/MyEnv/begin}{\expandafter\shorthandoff\expandafter{\shorthandlist}}

\begin{document} \begin{MyEnv}[]{1e-1}{1e4} \draw[thick,blue,dashed] (axis cs:1,0) -- (axis cs:100,1); \addplot[variable=t,domain=1e-1:1e4] gnuplot {(t>100)?0.2:0.5}; \end{MyEnv} \end{document}

Rushi
  • 837
Javier Bezos
  • 10,003
  • This should do for what I have in mind. All I have to do is add the hook \AddToHook{env/MyEnv/begin}{\expandafter\shorthandoff\expandafter{\shorthandlist}} and things work out. Thanks! Would you mind if I add the hook to your answer just for completeness? – Rushi Feb 06 '24 at 04:59
  • @Rushi Not at all. Please, do it! Maybe babel should provide such a list is a more manageable way (or even something like \shorthandoff{all}). – Javier Bezos Feb 06 '24 at 07:24