Cách chuyển các đối số macro (# 1, # 2, ..) cho các biến Lua

Oct 05 2020

Câu hỏi này có lẽ là tầm thường, nhưng tôi đã bắt đầu khám phá Lua (La) TeX vài giờ trước nên hãy chịu khó với tôi.

MWE như sau:

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

Tôi biết tôi có thể đưa \newcommandvào textệp và sau đó gọi directluabên trong định nghĩa lệnh, nhưng trong trường hợp sử dụng thực tế của tôi, tôi đang lặp lại một bảng trong đó các phím là tên lệnh, vì vậy tôi cần để nguyên như vậy.

CHỈNH SỬA : Vì câu hỏi ban đầu của tôi có thể là một chút vấn đề về XY, tôi đăng trường hợp sử dụng thực tế của mình bên dưới.

Mục tiêu của tôi là: đưa ra một loạt các môi trường định lý được xác định bởi thmtoolsgói, xác định lại chúng bằng cách nhúng chúng vào một tcolorboxmôi trường.

Tôi đã bắt đầu làm điều này thông qua expl3nhưng rất nhanh chóng thất vọng, một phần vì sự kém cỏi của tôi trong cách lập trình LaTeX3, một phần vì lập trình trong LaTeX quá khó so với mọi ngôn ngữ lập trình "bình thường" khác (đối với vòng lặp, câu lệnh if, v.v. ), đó là lý do tại sao bắt đầu tìm hiểu sâu hơn về LuaTeX.

Bây giờ đến mã. Tôi có cái bàn này

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

nơi các phím được tên môi trường (một lần nữa, đến từ thmtools), và các giá trị là tcolorboxtùy chọn (ở đây definition, example, theoremvà proofmột loạt các phong cách tcolorbox.

Cách tôi lặp qua bảng đó (và phần còn lại của tệp .lua được bao gồm qua \directlua) như sau:

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

Trả lời

1 Mico Oct 05 2020 at 20:05

Tôi nghĩ đơn giản hơn là thiết lập macro LaTeX trong tệp .tex và nhóm mã Lua trong các hàm có thể chấp nhận và trả về đối số.

Ví dụ: test.texcó thể như sau:

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

trong khi test.luacó thể chứa

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

Lưu ý rằng các chuỗi được tích lũy bởi tex.printkhông được trả về TeX cho đến khi đoạn Lua hoàn thành, vì vậy không có Lua nào hoạt động tại điểm #1được xử lý làm đối số bar. Vì vậy, để trả lời câu hỏi của bạn như đã viết, bạn cần nhập lại Lua tại thời điểm đó như được hiển thị ở đây.

bản in này

arg is: barbaz

Từ Lua, hiển thị chuỗi barđã được chuyển đến Lua.

và sắp chữ cái này, tôi nghĩ rằng đầu ra dự định của bạn.

Tuy nhiên, đây gần như chắc chắn không phải là cách tốt nhất để tiếp cận trường hợp sử dụng thực của bạn.

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