3

I use a macro \mychoice{item a, item b, items c,…} that returns one of the items of the comma-separated-list determined by an external counter based on the \docsvlist macro from etoolbox. In simple text, this macro works fine, but when I try to use it in a \directlua{} from Lua(La)TeX, it raises strange (at least for me) errors.

MWE:

\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}
\begin{luacode*}
 function dummy(argument)
 end
\end{luacode*}

\newcounter{choicecounter}
\newcounter{argcounter}

\newcommand{\mychoice}[1]{
    \setcounter{argcounter}{0}
    \renewcommand*{\do}[1]{
        \stepcounter{argcounter}
        \csedef{argcounter\arabic{argcounter}}{##1}}
    \docsvlist{#1}
    \csuse{argcounter\arabic{choicecounter}}
}

\newcommand{\main}[1]{%
    \setcounter{choicecounter}{#1}
    hello world \mychoice{one,{two,three}}
    \directlua{dummy(\luastring{\mychoice{foo,bar}})}
}

\begin{document}
\main{1}

\main{2}
\end{document}

So this version raises the error. If you comment out the \directlua it compiles fine.

What am I doing wrong? Or is there a bug somewhere?

PS: Replacing \directlua with \luadirect or \luaexec from luacode-package or leaving out \luastring-command doesn't change anything.

  • 2
    your command is not expandable. You can't fed abitrary stuff to directlua, it must expand to something lua can handle. – Ulrike Fischer Dec 7 '18 at 11:41
  • And how can I make it expandable? Or rather: What is preventing it from being expanded to something, lua can handle? – Toscho Dec 7 '18 at 13:59
5

You can use expl3 and \clist_item:nn to select an item in a list. This is expandable:

\documentclass{article}
\usepackage{luacode}
\usepackage{expl3}
\begin{luacode*}
 function dummy(argument)
  tex.sprint("lua: ".. argument)
 end
\end{luacode*}

\ExplSyntaxOn
\newcommand{\main}[1]{%
    hello~world~\clist_item:nn{one,{two,three}}{#1}\par
    \directlua{dummy(\luastring{\clist_item:nn{foo,bar}{#1}})}
}
\ExplSyntaxOff

\begin{document}
\main{1}

\main{2}
\end{document}

As egreg suggested in the comments an real expl3 version would use \lua_now:e instead of \directlua:

 \lua_now:e {dummy("\lua_escape:e{\clist_item:nn{foo,bar}{#1}}")}

enter image description here

  • \lua_now:e {dummy("\lua_escape:e{\clist_item:nn{foo,bar}{#1}}")} – egreg Dec 7 '18 at 23:03
  • @egreg yes, but perhaps this looks to frightening for someone not used to expl3 ;-) (but I added it). – Ulrike Fischer Dec 7 '18 at 23:07
  • 1
    That's not such a good idea. expl3 takes ages to load in LuaTeX because of the huge Unicode tables. – Henri Menke Dec 8 '18 at 6:09
  • Comments are not for extended discussion; this conversation has been moved to chat. – Joseph Wright Dec 8 '18 at 7:51
  • Thank you @UlrikeFischer . This answer is doing exactly what I want. I didn't think, that expl3 has so easy solutions for problems, where I only find highly complex solutions in LaTeX2e based on keyval-package or definition of useless commands as in my try. – Toscho Dec 8 '18 at 11:49
2

The most important thing you need to do is replace \luastring with \luastringN -- the N stands for "perform NO expansion" -- in the definition of the \main macro. In addition, you need to disallow all those gratuitous whitespaces, by placing % at various line ends inside the definitions of the \main and \mychoice macros.

For the following MWE, I borrowed the form of the dummy function from Ulrike's answer.

enter image description here

\documentclass{article}
\usepackage{etoolbox}
\usepackage{luacode} % for 'luacode' environment and '\luastringN' macro
\begin{luacode}
function dummy ( argument )
   tex.sprint ( "lua: " .. argument )
end
\end{luacode}

\newcounter{choicecounter}
\newcounter{argcounter}

\newcommand{\mychoice}[1]{%
    \setcounter{argcounter}{0}%
    \renewcommand*{\do}[1]{%
        \stepcounter{argcounter}%
        \csedef{argcounter\arabic{argcounter}}{##1}}%
    \docsvlist{#1}%
    \csuse{argcounter\arabic{choicecounter}}%
}

\newcommand{\main}[1]{%
    \setcounter{choicecounter}{#1}%
    \mychoice{one,{two,three}}

    \directlua{dummy(\luastringN{\mychoice{one,{two,three}}})}
}

\begin{document}
1 --- \main{1}

\medskip
2 --- \main{2}
\end{document}
  • I'm pretty sure that Lua can extract an item from a comma separated list of items. – egreg Dec 7 '18 at 23:40
  • @egreg - It sure can. My answer was meant to address the OP's opening remark, viz., "In simple text, [the \mychoice] macro works fine, but when I try to use it in a \directlua{} from Lua(La)TeX, it raises strange ... errors." The point of my answer is that all the OP really has to do is change the way the \mychoice macro is called from inside the \directlua directive: One has to make sure that \mychoice{one,{two,three}}} doesn't get expanded prematurely, by replacing \luastring with \luastringN. (Getting rid of the gratuitous whitespaces is nice, but not crucial.) – Mico Dec 7 '18 at 23:48
  • Thank you, @Mico for your answer, but it doesn't fit my needs. The contents of luastring have to be expanded in my real problem, because dummy will store these contents and some later function will use these contents. By then, the choice-counter will have changed. I will see if storing the value of the choice-counter separately will help. – Toscho Dec 8 '18 at 11:38
  • @Toscho - Ah, I was definitely quite unaware of your objectives. I was mistakenly under the impression that you simply wanted to get the existing \mychoice macro to work inside a \directlua directive. – Mico Dec 8 '18 at 15:03
  • @Mico And I didn't state my objective in that detail. – Toscho Dec 9 '18 at 10:54

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.