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
\expandafter
s and\csname
s 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.
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 findfoo
(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 theunravel
package would use, though my steps might not be the same that package would show):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):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:Now the second
\csname
grabs/expands tokens until it finds\endcsname
and turn the found string into a control sequence:and
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 likeThe first
\csname
finally finds its\endcsname
and this will becomeNow also the first
\csname
had its step of expansion from\expandafter
, so it'll be removed and\stuff
put back, so this eventually becomesand 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.