2

I expect a user to write something like:

\pgfkeys{
  latex/.append style={
    add to preamble={
      \def\sayhello#1{Hello #1.}
    }
  },
}

but this does not work, as #1 is understood as the first argument of latex’s style while I would expect it to be just the symbol #. So I need to double the number of hashes, like:

\pgfkeys{
  latex/.append style={
    add to preamble={
      \def\sayhello##1{Hello ##1.}
    }
  },
}

However, there is no reason to define a #1, since latex expects anyway no argument.

Is it possible, somehow, to say that add to preamble should not try to interpret the inner hashes as arguments? I guess it might be possible to play with catcodes, but importantly these catcodes should be added once for all in the add to preamble definition but it's not a code that I want the end user to type (basically they should type more or less exactly what I wrote in the first code).

MWE

\documentclass[]{article}
\usepackage{tikz}
\begin{document}

\ExplSyntaxOn

%% See also https://tex.stackexchange.com/questions/695432/latex3-latex-doubles-the-number-of-hashes-when-storing-them-in-string/695460#695460 \cs_generate_variant:Nn \str_replace_all:Nnn { Nnx } \cs_set:Nn \str_set_hash_robust:Nn { \str_set:Nn {#1} {#2} \str_replace_all:Nnx {#1} { ## } { \c_hash_str } }

\NewDocumentCommand{\defineString}{m}{ \str_set_hash_robust:Nn \l_test_str {#1} }

\NewDocumentCommand{\showString}{}{ \show \l_test_str }

\ExplSyntaxOff

% To show that in a normal setting hashes are not doubled \defineString{Hey \notexistingbutnoproblem #} \showString

%%% Code of the library: feel free to do anything here \pgfkeys{ latex/.style={ add to preamble/.code={\defineString{##1}}, show string/.code={\showString}, }, add to style/.style 2 args={ #1/.append style={ #2 }, }, }

%%% Code of the user: ideally modify as little as possible, especially no catcode stuff. %%% I’m fine with defining "my append to style={latex}{add to preamble={...}}" but no catcode stuff here. \pgfkeys{ %% I don't want the user to use ##, a single # should be enough. %% add to style={latex}{ %% This should contain only # instead of ## % Works: add to preamble={\def\sayhello##1{Hello ##1}} % Fails: % add to preamble={\def\sayhello#1{Hello #1}} }, latex, show string }

\end{document}

EDIT

I found (EDIT2 ACTUALLY IT IS NOT WORKING PERFECTLY AS IF THE CODE CONTAINS PLACEHOLDERS THEY ARE REPLACED AS WELL AND CAN BREAK THE SYSTEM, I NEED A MORE SPECIFIC REPLACEMENT FUNCTION) a solution by replacing latex/.append style={…} with a custom stuff I created add to style={latex}{…}. This converts the second argument to a string, then it converts # to ##, put it in a strings, create (using placeholders with my lib robustExternalize, with expanded after I would get extra {…} around the string not sure why, certainly catcode magic). Then I add \pgfkeys-stuff around, and I rescan this string (using again robustExternalize)… I guess there is a better solution, but it is the only solution I found for now.

\documentclass[]{article}
\usepackage{tikz}
\usepackage{robust-externalize} % Allows manipulation with placeholder, not even sure how to do it efficiently without. Copy .sty from https://github.com/leo-colisson/robust-externalize (freshly added in CTAN)
\begin{document}

\ExplSyntaxOn

%% See also https://tex.stackexchange.com/questions/695432/latex3-latex-doubles-the-number-of-hashes-when-storing-them-in-string/695460#695460 \cs_generate_variant:Nn \str_replace_all:Nnn { Nnx } \cs_set:Nn \str_set_hash_robust:Nn { \str_set:Nn {#1} {#2} \str_replace_all:Nnx {#1} { ## } { \c_hash_str } } \cs_generate_variant:Nn \str_set_hash_robust:Nn { cn } % Double the number of hashes... quite dirty but cannot find any solution or the user need to double it itself % \cs_set:Nn \str_set_hash_double:Nn { \str_set:Nn {#1} {#2} \str_replace_all:Nnx {#1} { ## } { \c_hash_str \c_hash_str } }

\NewDocumentCommand{\defineString}{m}{ \str_set_hash_robust:Nn \l_test_str {#1} }

\NewDocumentCommand{\strSetDoubleHash}{mm}{ \str_set:Nn {#1} {#2} \str_replace_all:Nnx {#1} { ## } { \c_hash_str \c_hash_str } }

\NewDocumentCommand{\showString}{}{ \show \l_test_str }

\ExplSyntaxOff

% To show that in a normal setting hashes are not doubled \defineString{Hey \notexistingbutnoproblem #} \showString

%%% Code of the library: feel free to do anything here \pgfkeys{ latex/.style={ add to preamble/.code={\defineString{##1}}, show string/.code={\showString}, }, add to style/.code 2 args={% \strSetDoubleHash{\robExtTmpStr}{#2} % Sadly, \expanded{\noexpand } does not work, as I get extra {} around the def, creating a group % so the simpler seems to use this library ^^ \robExtPlaceholderFromString{ROBEXT_TMP}{\robExtTmpStr}% \robExtEvalPlaceholder{% \pgfkeys{% #1/.append style={ROBEXT_TMP},% }% }% \robExtRemovePlaceholder{ROBEXT_TMP}% let us clean our variables }, }

%%% Code of the user: ideally modify as little as possible, especially no catcode stuff. %%% I’m fine with defining "my append to style={latex}{add to preamble={...}}" but no catcode stuff here. \pgfkeys{ %% I don't want the user to use ##, a single # should be enough. %%
add to style={latex}{ add to preamble={\def\sayhello#1{Hello #1}\foo}, }, latex, show string }

\end{document}

If you know a better solution, please let me know ^^

tobiasBora
  • 8,684
  • Is \def\sayhello#1{Hello #1} supposed to be used as it is in the document or will it get written to an file to be read later? In the latter, a definition of add to style/.style 2 args={#1/.append style/.expanded=\detokenize{#2}} will have \l_test_str contain \def \sayhello #1{Hello #1}. – Qrrbrbirlbel Sep 08 '23 at 19:17
  • Otherwise, Q509697 seems related but is the opposite problem, I think? – Qrrbrbirlbel Sep 08 '23 at 19:21
  • @Qrrbrbirlbel thanks but it seems to do weird things, for instance to brackets, as I get errors like /robExt/{ some key does not exists. I need to investigate it further when I get back to a computer. Regarding the other question, it seems to do the other direction but I'm not 100% sure it does not help here. And the goal is to have the def put in a string, and this string may be written to a file or evaluated depending on whether externalization is enabled or not. – tobiasBora Sep 09 '23 at 10:29

0 Answers0