3

This question is probably trivial, but I started exploring Lua(La)TeX a couple of hours ago so bear with me.

The MWE is the following:

test.tex:

\documentclass{article}
\directlua{require("test.lua")}
\begin{document}
\foo{bar}
\end{document}

test.lua:

tex.print("\\newcommand{\\foo}[1]{")
tex.print("\\texttt{#1}")
-- arg = ?? how do I pass #1 to arg ??
-- arg = arg .. " baz"
-- tex.print("\\textit{" .. arg .. "}")
tex.print("}")

I know I could put \newcommand in the tex file and then call directlua inside the command definition, but in my actual use case I'm looping over a table where the keys are the command names, so I need to leave that as is.

EDIT: As my initial question might have been a bit of an XY problem, I'm posting my real use case below.

My goal is: given a bunch of theorem environments defined by the thmtools package, redefine them by embedding them in a tcolorbox environment.

I started doing this via expl3 but got frustrated very quickly, partly because of my incompetence in the LaTeX3 way of programming, partly because programming in LaTeX is so painful compared to every other "normal" programming language (for loops, if statements, etc..), which is why is started diving deeper into LuaTeX.

Now to the code. I have this table

boxed_theorems = {
  definition = "definition",
  example = "example",
  lemma = "theorem",
  theorem = "theorem",
  corollary = "theorem",
  proof = "proof",
}

where the keys are environment names (again, coming from thmtools), and the values are tcolorbox options (here definition, example, theorem and proof are a bunch of tcolorbox styles.

The way I loop over that table (and the rest of the .lua file included via \directlua) is the following:

tex.print("\\ExplSyntaxOn")

for theorem,tcolorbox_theorem in pairs(boxed_theorems) do
  -- copy <theorem_name> in a new environment inner<theorem_name>
  tex.print("\\let\\inner" .. theorem .. "\\" .. theorem)
  tex.print("\\let\\endinner" .. theorem .. "\\end" .. theorem)

  tex.print("\\RenewDocumentEnvironment{ " .. theorem .. " }{ O{} }{")

  -- I want to be able to call the new environment like this:
  --
  -- \begin{theorem}[name={foo}, label={bar}, tcolorbox={baz}]
  --
  -- where 'name={foo}, label={bar}' is the argument of the
  -- innertheorem and should be assigned to 'theorem_options',
  -- while '{baz}' is an argument of the embedding tcolorbox and
  -- should be assigned to 'tcolorbox_local'.
 
  -- I haven't got that far yet (I need to create a function that
  -- parses #1, hence the original post), so for now they are just
  -- left empty.
  theorem_options = ""
  tcolorbox_local = ""

  -- The rest is pretty self-explanatory
  tex.print("\\begin{tcolorbox}[" .. tcolorbox_theorem .. ","
                                  .. tcolorbox_local .. "]")
  if theorem_options == "" then
    tex.print("\\begin{inner" .. theorem .. "}")
  else
    tex.print("\\begin{inner" .. theorem .. "}[" .. theorem_options .. "]")
  end
  tex.print("}{")
  tex.print("\\end{inner" .. theorem .. "}")
  tex.print("\\end{tcolorbox}")
  tex.print("}")
end

tex.print("\\ExplSyntaxOff")
3
  • I think the answer to your question is tex.print(\\directlua{luaarg='#1'}) but I am not sure that is the answer you want. Commented Oct 5, 2020 at 13:23
  • 2
    Please elaborate on "I'm looping over a table where the keys are the command names". Which keys? Which command names? Commands to do what?
    – Mico
    Commented Oct 5, 2020 at 13:30
  • 1
    @Mico I've updated my question with my real use case.
    – noibe
    Commented Oct 5, 2020 at 15:38

2 Answers 2

1

I think it's more straightforward to set up LaTeX macros in the .tex file and to group the Lua code in functions that can accept and return arguments.

E.g., test.tex might be as follows:

\documentclass{article}
\directlua{require("test.lua")}
\newcommand\foo[1]{\directlua{foo("#1")}}
\begin{document}
\foo{bar}
\end{document}

while test.lua might contain

function foo ( s )
   tex.sprint ( "\\textit{"..s.."}" )
end
5
  • I know, but as I said, in my actual code I need to loop over a table where the keys are environments, and for every key I need to do a \RenewDocumentEnvironment{ <environment> }.... Since looping in TeX is a nightmare, I'd like to do that in Lua.
    – noibe
    Commented Oct 5, 2020 at 13:12
  • btw, what's the difference tex.print and tex.sprint?
    – noibe
    Commented Oct 5, 2020 at 13:13
  • 1
    @noibe I think we might need an example showing more of your real problem: without context, either Mico's approach or a loop in TeX sound fine
    – Joseph Wright
    Commented Oct 5, 2020 at 13:15
  • @noibe - tex.sprint prints a string (here, "sprint" stands for "string print", not "run very fast over a short distance") and makes sure not to affix a line break. tex.print may or may not affix a line break.
    – Mico
    Commented Oct 5, 2020 at 14:57
  • @JosephWright I've updated my question with my real use case.
    – noibe
    Commented Oct 5, 2020 at 15:38
1

Note that the strings accumulated by tex.print are not returned to TeX until the Lua chunk completes so there is no Lua active at the point that #1 is processed as the argument bar. So to answer your question as written you need to re-enter Lua at that point as shown here.

this prints

arg is: barbaz

From Lua, showing the string bar was passed to Lua.

and typesets this, which is I think your intended output.

enter image description here

However this is almost certainly not the best way of approaching your real use case.

\documentclass{article}
\directlua{require("test.lua")}
\begin{document}
\foo{bar}

\directlua{
texio.write_nl('arg is: ' .. arg .. '\string\n')
}
\end{document}

test.lua

tex.print("\\newcommand{\\foo}[1]{")
tex.print("\\texttt{#1}")
tex.print("\\directlua{arg='#1' arg = arg .. 'baz' tex.print('\\\\textit{' .. arg .. '}')}")
tex.print("}")

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .