2

I'm trying to issue TeX warnings from within \directlua with accurate line numbers (pointing to the offending line in the .tex document).

When I compile the MWE below with lualatex, \TestTex issues a warning that correctly points to line 40. However, \TestLua and \TestLuaIndirect both issue warnings pointomg to line 1.

Any help would be much appreciated. Thank you!

\documentclass{article}

\ExplSyntaxOn

\msg_new:nnn { test } { test-warning } { #1 ~ \msg_line_context: }

\NewDocumentCommand { \TestTex } { } { \ExplSyntaxOn \msg_warning:nnn { test } { test-warning } { tex ~ warning } \ExplSyntaxOff }

\NewDocumentCommand { \TestLua } { } { \directlua { tex.sprint('\ExplSyntaxOn' .. '\msg_warning:nnn { test } { test-warning }' .. '{ lua ~ warning }' .. '\ExplSyntaxOff') } }

\NewDocumentCommand { \TestLuaIndirect } { } { \directlua { tex.sprint('\TestTex') } }

\ExplSyntaxOff

\begin{document}

Test.

\TestTex

\TestLua

\TestLuaIndirect

\end{document}

steve
  • 2,154
  • 1
    You could use (from Lua) something like luatexbase.module_warning(module_name, message) instead. – Max Chernoff Apr 02 '23 at 05:33
  • @MaxChernoff I was completely unaware of this method, but it's exactly the sort of thing I was looking for. Thank you so much! – steve Apr 02 '23 at 12:06

1 Answers1

2

Basicaislly sprint creates a new "file-like layer" in the input stack (imagine that a \input{tmpfile} is executed, and the warning itself is on line 1 of the temporary file). You want to unroll it "as if it's executed from a macro".

Speaking of which, \ExplSyntaxOn inside any {...} is almost-always wrong: macros - Why doesn't \makeatletter work inside \newcommand? - TeX - LaTeX Stack Exchange

One possible workaround follows, use \futurelet to force unroll the input stack, similar to the case in my question/answer luatex - How can I make macros called from tex.print tail-recursive? - TeX - LaTeX Stack Exchange. Note that the sprint must be the last one in the \directlua block for this to work.

\documentclass{article}

\ExplSyntaxOn

\msg_new:nnn { test } { test-warning } { #1 ~ \msg_line_context: }

\NewDocumentCommand { \TestTex } { } { \msg_warning:nnn { test } { test-warning } { tex ~ warning } }

\NewDocumentCommand { \TestLua } { } { \directlua { tex.sprint('\ExplSyntaxOn\def\tmp{' .. '\msg_warning:nnn { test } { test-warning }' .. '{ lua ~ warning }' .. '}\ExplSyntaxOff\futurelet\tmpa\tmp') } }

\NewDocumentCommand { \TestLuaIndirect } { } { \directlua { tex.sprint('\futurelet\tmpa\TestTex') } }

\ExplSyntaxOff

\begin{document}

Test.

\TestTex

\TestLua

\TestLuaIndirect

\end{document}

Of course the disadvantage is that the catcode is fixed.

An alternative is to print a token directly:

\documentclass{article}

\ExplSyntaxOn

\msg_new:nnn { test } { test-warning } { #1 ~ \msg_line_context: }

\NewDocumentCommand { \TestTex } { } { \msg_warning:nnn { test } { test-warning } { tex ~ warning } }

\NewDocumentCommand { \TestLuaIndirect } { } { \directlua { token.put_next(token.create('TestTex')) } }

\ExplSyntaxOff

\begin{document}

Test.

\TestTex

\TestLuaIndirect

\end{document}

Refer to Can the Lua part of LuaTeX know about tokens? and texdoc luatex for some documentation.

user202729
  • 7,143
  • This is fantastic information, thank you! One additional question though: how could I pass arguments to \TestTex inside \TestLuaIndirect in the second approach without leaving Lua? (For example, a warning message containing a few local Lua variables.) – steve Apr 02 '23 at 12:05
  • @steve What do you mean? You already leave Lua by executing some TeX code. (although the last link is basically all you have to work with in Lua.) – user202729 Apr 03 '23 at 08:05
  • Ah, I didn't realize that token.put_next(...) exits Lua, that answers the question though (meaning it's not possible). – steve Apr 03 '23 at 13:55