Is there a way to use string manipulations to make macro names

macrosstrings

Bottom line up front: what is a convenient way to input a particular character string into a \newcommand call so it can be manipulated to create multiple macro names? In particular, input (say) ABC so that a savebox \ABCbox is created, from which a macro \ABC is then defined using \ABCbox, and returning that macro for repeated use later on. I suspect I would prefer a Lua suggestion, but am a complete novice in how Lua interacts with LaTeX, so will likely need some hand-holding.


As a group theorist, I use "k" for conjugacy classes, but want one that is (in spirit) an overlay of $\ell$ on $\mathit k$ to have a loopy "k" in the same way \ell is a loopy "l". Ultimately, I wrote tikz code that created the glyph I wanted, and wrote a \newcommand to name the macro \kay that printed that glyph. However, I naively included the tikz code directly in the \newcommand call, which meant that the tikz code was newly compiled every time \kay was called, which was a few hundred times; compile times increased considerably. Due to the answer given at Long Compilation Time: Tikz Accents, I discovered saveboxes, and compile times were demonstrably faster.

As an academic exercise, I then decided to create other personal glyphs using similar methods, and found myself reusing the same "boxing" code over and over in creating the corresponding saveboxes. Hence, I wrote the following macro which would take as input the tikzpicture (and some other parameters) and output the corresponding savebox.

\newcommand\createABCbox[5]{%
\newsavebox#1
\savebox#1{%
\mathalpha{
\hspace{#2pt}
\raisebox{#3pt}{#5}%
\hspace{#4pt}}}}

The code would be used in the following way (consider this an MWE, the actual tikz code is much more elaborate):

\createABCbox{\ehhbox}{1}{1}{.5}
{
\begin{tikzpicture}
\node at (0,0){\(h\)};
\end{tikzpicture}
}
\newcommand \ehh{\usebox{\ehhbox}}

This got me to thinking. While this greatly reduced the amount of work I needed by putting it in a macro call, there should be a way to get the obvious additional savings. (As well, I suspect a solution to this problem will prove useful to another three situations I face.) What I would really like is to make a command \createABC that takes as its first input just the character string "ehh" and somehow manipulates it to create the character strings "\ehhbox" and "\ehh", with the newly developed strings then being used at the LaTeX level as the actual macro names being defined. Hence, running \createABC with input string "XYZ" would create the macro call \XYZ and the savebox \XYZbox.

As for my efforts in this direction, I have looked at the packages stringstrings and xstring, but both seem to deal more with strings which will be printed, rather than creating something that is recognized by a LuaLaTeX compiler as a macro name. I do admit I didn't delve too deeply into either of these, so I may have missed something.

Ideally, I would like to perform this task in Lua (at which I am a complete novice), but

  • I don't know the correct way to place an argument (in this example, #1) into a form Lua recognizes as a string, and

  • every time I try to insert Lua code into a LaTeX \newcommand, I get an error.

As an example of the second point, using the package luacode, the code

\begin{document}

\begin{luacode}
tex.sprint("hello world")
\end{luacode}

\end{document}

compiles correctly. However, if I wrap the Lua portion in a newcommand call such as

\begin{document}

\newcommand\AAA
{
\begin{luacode}
tex.sprint("hello world")
\end{luacode}
}

\AAA
\end{document}

I get the following error message.

Runaway argument?
! File ended while scanning use of \luacode@grab@lines.

For completeness, the entire preamble presently is…

\documentclass{article}
\special{papersize=8.5in,11in}
\pagestyle{empty}
\usepackage{bm,comment,luacode,mathtools,scalefnt,tikz}
\usetikzlibrary{arrows.meta,calc}

Best Answer

This is essentially the same as @gernot's answer but reduces the number of \expandafters and \csnames making the code more readable, imho.

The approach uses two steps of processing, the first step just reads in the first argument (the others are curried) and creates the macro names from it, resulting in two new arguments. The next step then gets all the arguments.

\documentclass[]{article}

\usepackage{tikz}

\makeatletter
\newcommand\newABC[1]
  {%
    % #1: name for macro and box
    % #2: before   (curried)
    % #3: raise    (curried)
    % #4: after    (curried)
    % #5: contents (curried)
    \expandafter\newABC@\csname #1\expandafter\endcsname\csname #1box\endcsname
  }
\newcommand\newABC@[6]
  {%
    % #1: macro
    % #2: box-macro
    % #3: before
    % #4: raise
    % #5: after
    % #6: contents
    \newsavebox#2%
    \sbox#2{\mathalpha{\hspace{#3pt}\raisebox{#4pt}{#6}\hspace{#5pt}}}%
    \newcommand#1{\usebox#2}%
  }
\makeatother

\newABC{ehh}{1}{1}{.5}
{%
\begin{tikzpicture}
\node at (0,0){\(h\)};
\end{tikzpicture}%
}

\begin{document}
A\ehh b
\end{document}

enter image description here


As requested a few explanations on the code:

  • \csname expands all following tokens until it finds an \endcsname and the result is turned into a control sequence.

  • \expandafter steps over the next token (regardless which kind of token, an opening brace for instance is a token as well which could be stepped over with this) and expands the token after that one once (if that token isn't expandable nothing happens).

So \expandafter\stuff\csname foo\endcsname will result in \stuff being stepped over and \csname being expanded once. Within a single step of expansion \csname expands all following tokens until it finds an \endcsname and leaves everything in between as the name of a control sequence. In this case it'll find foo (letters don't expand further), and so after \csname is done the \expandafter will be removed from the input stream and \stuff put back, so the input will now contain \stuff\foo.

We can utilize the fact that \csname expands everything until it finds an \endcsname to build two control sequences at once (in the following the next thing TeX will evaluate will be preceded by |> and the tokens stored to be put back because TeX stepped over them will be preceded by || -- this is the same style the unravel package would use, though my steps might not be the same that package would show):

|> \expandafter\stuff\csname foo\expandafter\endcsname\csname bar\endcsname

will first step over \stuff, so the input will look like this (this is less than one step of expansion, more a step of processing):

|| \expandafter\stuff
|> \csname foo\expandafter\endcsname\csname bar\endcsname

Now \csname will start grabbing/expanding tokens, and because of \expandafter the \endcsname will not be found, instead TeX steps over it and expands what follows:

|| \expandafter\stuff
|| \csname foo\expandafter\endcsname
|> \csname bar\endcsname

Now the second \csname grabs/expands tokens until it finds \endcsname and turn the found string into a control sequence:

|| \expandafter\stuff
|| \csname foo\expandafter\endcsname
|| \csname bar
|> \endcsname

and

|| \expandafter\stuff
|| \csname foo\expandafter\endcsname
|| \bar

Now the second \csname is done with one step of expansion and the second \expandafter will be removed and the token which followed it put back, so the next step of processing would look like

|| \expandafter\stuff
|| \csname foo
|> \endcsname\bar

The first \csname finally finds its \endcsname and this will become

|| \expandafter\stuff
|| \foo\bar

Now also the first \csname had its step of expansion from \expandafter, so it'll be removed and \stuff put back, so this eventually becomes

|> \stuff\foo\bar

and now \stuff can do stuff.

Even though the above was visualized in many small steps of processing when we look at expansion steps this is all done in a single step, because \expandafter will in a single step expand the \csname and that will fully expand the remaining stuff in this one step.

Related Question