Como passar argumentos de macro (# 1, # 2, ..) para variáveis ​​Lua

Oct 05 2020

Esta pergunta é provavelmente trivial, mas comecei a explorar Lua (La) TeX algumas horas atrás, então tenha paciência comigo.

O MWE é o seguinte:

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("}")

Eu sei que poderia colocar \newcommando texarquivo e, em seguida, chamar directluadentro da definição de comando, mas no meu caso de uso real, estou fazendo um loop em uma tabela onde as chaves são os nomes dos comandos, então preciso deixar como está.

EDITAR : Como minha pergunta inicial pode ter sido um pouco um problema XY, estou postando meu caso de uso real abaixo.

Meu objetivo é: dado um monte de ambientes de teoremas definidos pelo thmtoolspacote, redefina-os incorporando-os em um tcolorboxambiente.

Comecei a fazer isso via, expl3mas fiquei frustrado muito rapidamente, em parte por causa da minha incompetência na forma de programação LaTeX3, em parte porque a programação em LaTeX é tão dolorosa em comparação com qualquer outra linguagem de programação "normal" (para loops, declarações if, etc. ), que é o motivo pelo qual começou a mergulhar mais fundo em LuaTeX.

Agora para o código. Eu tenho esta mesa

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

onde as chaves são nomes de ambiente (de novo, vindos de thmtools), e os valores são tcolorboxopções (aqui definition, example, theoreme proofsão um bando de estilos tcolorbox.

A maneira como faço um loop sobre essa tabela (e o resto do arquivo .lua incluído via \directlua) é a seguinte:

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")

Respostas

1 Mico Oct 05 2020 at 20:05

Eu acho que é mais simples configurar macros LaTeX no arquivo .tex e agrupar o código Lua em funções que podem aceitar e retornar argumentos.

Por exemplo, test.texpode ser o seguinte:

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

enquanto test.luapode conter

function foo ( s )
   tex.sprint ( "\\textit{"..s.."}" )
end
DavidCarlisle Oct 05 2020 at 20:34

Observe que as strings acumuladas por tex.printnão são retornadas ao TeX até que o trecho Lua seja concluído, portanto, não há Lua ativa no ponto que #1é processado como o argumento bar. Portanto, para responder à sua pergunta da forma como foi escrita, você precisa entrar novamente em Lua nesse ponto, conforme mostrado aqui.

isso imprime

arg is: barbaz

De Lua, mostrar a string barfoi passado para Lua.

e compõe isso, que acho que é a saída pretendida

No entanto, quase certamente essa não é a melhor maneira de abordar seu caso de uso real.

\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("}")